Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> is used to have a deterministic output of the toString * method of the union type since this output is used in tests. */ static final Comparator<JSType> ALPHA = new Comparator<JSType>() { public int compare(JSType t1, JSType t2) { return t1.toString().compareTo(t2.toString()); } }; // A flag set on enum definition tree nodes public static final int ENUMDECL = 1; public static final int NOT_ENUMDECL = 0; final JSTypeRegistry registry; JSType(JSTypeRegistry registry) { this.registry = registry; } /** * Utility method for less verbose code. */ JSType getNativeType(JSTypeNative typeId) { return registry.getNativeType(typeId); } /** * Gets the docInfo for this type. By default, documentation cannot be * attached to arbitrary types. This must be overridden for * programmer-defined types. */ public JSDocInfo getJSDocInfo() { return null; } /** * Returns a user meaningful label for the JSType instance. For example, * Functions and Enums will return their declaration name (if they have one). * Some types will not have a meaningful display name. Calls to * hasDisplayName() will return true IFF getDisplayName() will return null * or a zero length string. * * @return the display name of the type, or null if one is not available */ public String getDisplayName() { return null; } /** * @return true if the JSType has a user meaningful label. */ public boolean hasDisplayName() { String displayName = getDisplayName(); return false; } boolean isTheObjectType() { return false; } public boolean isStringValueType() { return false; } /** * Tests whether the type is a string (value or Object). * @return {@code this &lt;: (String, string)} */ public final boolean isString() { return this.isSubtype( getNativeType(JSTypeNative.STRING_VALUE_OR_OBJECT_TYPE)); } /** * Tests whether the type is a number (value or Object). * @return {@code this &lt;: (Number, number)} */ public final boolean isNumber() { return this.isSubtype( getNativeType(JSTypeNative.NUMBER_VALUE_OR_OBJECT_TYPE)); } public boolean isArrayType() { return false; } public boolean isBooleanObjectType() { return false; } public boolean isBooleanValueType() { return false; } public boolean isRegexpType() { return false; } public boolean isDateType() { return false; } public boolean isNullType() { return false; } public boolean isVoidType() { return false; } public boolean isAllType() { return false; } public boolean isUnknownType() { return false; } public boolean isCheckedUnknownType() { return false; } public boolean isUnionType() { return false; } public boolean isFunctionType() { return false; } public boolean isEnumElementType() { return false; } public boolean isEnumType() { return false; } boolean isNamedType() { return false; } public boolean isRecordType() { return false; } public boolean isTemplateType() { return false; } /** * Tests whether this type is an {@code Object}, or any subtype thereof. * @return {@code

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>} always succeed (such as * {@code undefined} compared to {@code null})</li> * <li>{@link TernaryValue#FALSE} if the comparison of values of * {@code this} type and {@code that} always fails (such as * {@code undefined} compared to {@code number})</li> * <li>{@link TernaryValue#UNKNOWN} if the comparison can succeed or * fail depending on the concrete values</li> * </ul> */ public TernaryValue testForEquality(JSType that) { return testForEqualityHelper(this, that); } TernaryValue testForEqualityHelper(JSType aType, JSType bType) { if (bType.isAllType() || bType.isUnknownType() || bType.isNoResolvedType() || aType.isAllType() || aType.isUnknownType() || aType.isNoResolvedType()) { return UNKNOWN; } boolean aIsEmpty = aType.isEmptyType(); boolean bIsEmpty = bType.isEmptyType(); if (aIsEmpty || bIsEmpty) { if (aIsEmpty && bIsEmpty) { return TernaryValue.TRUE; } else { return UNKNOWN; } } if (aType.isFunctionType() || bType.isFunctionType()) { JSType otherType = aType.isFunctionType() ? bType : aType; // In theory, functions are comparable to anything except // null/undefined. For example, on FF3: // function() {} == 'function () {\n}' // In practice, how a function serializes to a string is // implementation-dependent, so it does not really make sense to test // for equality with a string. JSType meet = otherType.getGreatestSubtype( getNativeType(JSTypeNative.OBJECT_TYPE)); if (meet.isNoType() || meet.isNoObjectType()) { return TernaryValue.FALSE; } else { return TernaryValue.UNKNOWN; } } if (bType.isEnumElementType() || bType.isUnionType()) { return bType.testForEquality(aType); } return null; } /** * Tests whether {@code this} and {@code that} are meaningfully * comparable using shallow comparison. By meaningfully, we mean compatible * types that are not rejected by step 1 of the definition of the Strict * Equality Comparison Algorithm (11.9.6, page 56&ndash;57) of the * ECMA-262 specification.<p> */ public final boolean canTestForShallowEqualityWith(JSType that) { return this.isSubtype(that) || that.isSubtype(this); } /** * Tests whether this type is nullable. */ public boolean isNullable() { return this.isSubtype(getNativeType(JSTypeNative.NULL_TYPE)); } /** * Gets the least supertype of {@code this} and {@code that}. * The least supertype is the join (&#8744;) or supremum of both types in the * type lattice.<p> * Examples: * <ul> * <li>{@code number &#8744; *} = {@code *}</li> * <li>{@code number &#8744; Object} = {@code (number, Object)}</li> * <li>{@code Number &#8744; Object} = {@code Object}</li> * </ul> * @return {@code this &#8744; that}

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> */ public JSType getLeastSupertype(JSType that) { if (that.isUnionType()) { // Union types have their own implementation of getLeastSupertype. return that.getLeastSupertype(this); } return getLeastSupertype(this, that); } /** * A generic implementation meant to be used as a helper for common * getLeastSupertype implementations. */ static JSType getLeastSupertype(JSType thisType, JSType thatType) { boolean areEquivalent = thisType.isEquivalentTo(thatType); return areEquivalent ? thisType : filterNoResolvedType( thisType.registry.createUnionType(thisType, thatType)); } /** * Gets the greatest subtype of {@code this} and {@code that}. * The greatest subtype is the meet (&#8743;) or infimum of both types in the * type lattice.<p> * Examples * <ul> * <li>{@code Number &#8743; Any} = {@code Any}</li> * <li>{@code number &#8743; Object} = {@code Any}</li> * <li>{@code Number &#8743; Object} = {@code Number}</li> * </ul> * @return {@code this &#8744; that} */ public JSType getGreatestSubtype(JSType that) { if (that.isRecordType()) { // Record types have their own implementation of getGreatestSubtype. return that.getGreatestSubtype(this); } return getGreatestSubtype(this, that); } /** * A generic implementation meant to be used as a helper for common * getGreatestSubtype implementations. */ static JSType getGreatestSubtype(JSType thisType, JSType thatType) { if (thisType.isEquivalentTo(thatType)) { return thisType; } else if (thisType.isUnknownType() || thatType.isUnknownType()) { // The greatest subtype with any unknown type is the universal // unknown type, unless the two types are equal. return thisType.isEquivalentTo(thatType) ? thisType : thisType.getNativeType(JSTypeNative.UNKNOWN_TYPE); } else if (thisType.isSubtype(thatType)) { return filterNoResolvedType(thisType); } else if (thatType.isSubtype(thisType)) { return filterNoResolvedType(thatType); } else if (thisType.isUnionType()) { return ((UnionType) thisType).meet(thatType); } else if (thatType.isUnionType()) { return ((UnionType) thatType).meet(thisType); } else if (thisType.isObject() && thatType.isObject()) { return thisType.getNativeType(JSTypeNative.NO_OBJECT_TYPE); } return thisType.getNativeType(JSTypeNative.NO_TYPE); } /** * When computing infimums, we may get a situation like * inf(Type1, Type2) * where both types are unresolved, so they're technically * subtypes of one another. * * If this happens, filter them down to NoResolvedType. */ static JSType filterNoResolvedType(JSType type) { if (type.isNoResolvedType()) { // inf(UnresolvedType1, UnresolvedType2) needs to resolve // to the base unresolved type, so that the relation is symmetric. return type.getNativeType(JSTypeNative.NO_RESOLVED_TYPE); }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> else if (type instanceof UnionType) { UnionType unionType = (UnionType) type; boolean needsFiltering = false; for (JSType alt : unionType.getAlternates()) { if (alt.isNoResolvedType()) { needsFiltering = true; break; } } if (needsFiltering) { UnionTypeBuilder builder = new UnionTypeBuilder(type.registry); for (JSType alt : unionType.getAlternates()) { if (!alt.isNoResolvedType()) { builder.addAlternate(alt); } } return builder.build(); } } return type; } /** * Computes the restricted type of this type knowing that the * {@code ToBoolean} predicate has a specific value. For more information * about the {@code ToBoolean} predicate, see * {@link #getPossibleToBooleanOutcomes}. * * @param outcome the value of the {@code ToBoolean} predicate * * @return the restricted type, or the Any Type if the underlying type could * not have yielded this ToBoolean value * * TODO(user): Move this method to the SemanticRAI and use the visit * method of types to get the restricted type. */ public JSType getRestrictedTypeGivenToBooleanOutcome(boolean outcome) { BooleanLiteralSet literals = getPossibleToBooleanOutcomes(); if (literals.contains(outcome)) { return this; } else { return getNativeType(JSTypeNative.NO_TYPE); } } /** * Computes the set of possible outcomes of the {@code ToBoolean} predicate * for this type. The {@code ToBoolean} predicate is defined by the ECMA-262 * standard, 3<sup>rd</sup> edition. Its behavior for simple types can be * summarized by the following table: * <table> * <tr><th>type</th><th>result</th></tr> * <tr><td>{@code undefined}</td><td>{false}</td></tr> * <tr><td>{@code null}</td><td>{false}</td></tr> * <tr><td>{@code boolean}</td><td>{true, false}</td></tr> * <tr><td>{@code number}</td><td>{true, false}</td></tr> * <tr><td>{@code string}</td><td>{true, false}</td></tr> * <tr><td>{@code Object}</td><td>{true}</td></tr> * </table> * @return the set of boolean literals for this type */ public abstract BooleanLiteralSet getPossibleToBooleanOutcomes(); /** * Computes the subset of {@code this} and {@code that} types if equality * is observed. If a value {@code v1} of type {@code null} is equal to a value * {@code v2} of type {@code (undefined,number)}, we can infer that the * type of {@code v1} is {@code null} and the type of {@code v2} is * {@code undefined}. * * @return a pair containing the restricted type of {@code this} as the first * component and the restricted type of {@code that} as the second * element. The returned pair is never {@code null} even though its * components may be {@code null} */ public TypePair getTypesUnderEquality(JSType that) { // unions types if (that instanceof UnionType) { TypePair p = that.getTypesUnderEquality(this); return new TypePair(p.typeB, p.typeA);

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> } // other types switch (this.testForEquality(that)) { case FALSE: return new TypePair(null, null); case TRUE: case UNKNOWN: return new TypePair(this, that); } // switch case is exhaustive throw new IllegalStateException(); } /** * Computes the subset of {@code this} and {@code that} types if inequality * is observed. If a value {@code v1} of type {@code number} is not equal to a * value {@code v2} of type {@code (undefined,number)}, we can infer that the * type of {@code v1} is {@code number} and the type of {@code v2} is * {@code number} as well. * * @return a pair containing the restricted type of {@code this} as the first * component and the restricted type of {@code that} as the second * element. The returned pair is never {@code null} even though its * components may be {@code null} */ public TypePair getTypesUnderInequality(JSType that) { // unions types if (that instanceof UnionType) { TypePair p = that.getTypesUnderInequality(this); return new TypePair(p.typeB, p.typeA); } // other types switch (this.testForEquality(that)) { case TRUE: JSType noType = getNativeType(JSTypeNative.NO_TYPE); return new TypePair(noType, noType); case FALSE: case UNKNOWN: return new TypePair(this, that); } // switch case is exhaustive throw new IllegalStateException(); } /** * Computes the subset of {@code this} and {@code that} types under shallow * equality. * * @return a pair containing the restricted type of {@code this} as the first * component and the restricted type of {@code that} as the second * element. The returned pair is never {@code null} even though its * components may be {@code null}. */ public TypePair getTypesUnderShallowEquality(JSType that) { JSType commonType = getGreatestSubtype(that); return new TypePair(commonType, commonType); } /** * Computes the subset of {@code this} and {@code that} types under * shallow inequality. * * @return A pair containing the restricted type of {@code this} as the first * component and the restricted type of {@code that} as the second * element. The returned pair is never {@code null} even though its * components may be {@code null} */ public TypePair getTypesUnderShallowInequality(JSType that) { // union types if (that instanceof UnionType) { TypePair p = that.getTypesUnderShallowInequality(this); return new TypePair(p.typeB, p.typeA); } // Other types. // There are only two types whose shallow inequality is deterministically // true -- null and undefined. We can just enumerate them. if (this.isNullType() && that.isNullType() || this.isVoidType() && that.isVoidType()) { return new TypePair(null, null); } else { return new TypePair(this, that); } } /** * If this is a union type, returns a union type that does not include * the null or undefined type. */ public JSType restrictByNotNullOrUndefined() { return this; } /** * Checks whether {@code this} is a subtype of

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> } return false; } /** * Visit this type with the given visitor. * @see com.google.javascript.rhino.jstype.Visitor * @return the value returned by the visitor */ public abstract <T> T visit(Visitor<T> visitor); /** * Force this type to resolve, even if the registry is in a lazy * resolving mode. * @see #resolve */ public final JSType forceResolve(ErrorReporter t, StaticScope<JSType> scope) { ResolveMode oldResolveMode = registry.getResolveMode(); registry.setResolveMode(ResolveMode.IMMEDIATE); JSType result = resolve(t, scope); registry.setResolveMode(oldResolveMode); return result; } /** * Resolve this type in the given scope. * * The returned value must be equal to {@code this}, as defined by * {@link #isEquivalentTo}. It may or may not be the same object. This method * may modify the internal state of {@code this}, as long as it does * so in a way that preserves Object equality. * * For efficiency, we should only resolve a type once per compilation job. * For incremental compilations, one compilation job may need the * artifacts from a previous generation, so we will eventually need * a generational flag instead of a boolean one. */ public final JSType resolve(ErrorReporter t, StaticScope<JSType> scope) { if (resolved) { // TODO(nicksantos): Check to see if resolve() looped back on itself. // Preconditions.checkNotNull(resolveResult); if (resolveResult == null) { return registry.getNativeType(JSTypeNative.UNKNOWN_TYPE); } return resolveResult; } resolved = true; resolveResult = resolveInternal(t, scope); resolveResult.setResolvedTypeInternal(resolveResult); return resolveResult; } /** * @see #resolve */ abstract JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope); void setResolvedTypeInternal(JSType type) { resolveResult = type; resolved = true; } /** Whether the type has been resolved. */ public final boolean isResolved() { return resolved; } /** Clears the resolved field. */ public final void clearResolved() { resolved = false; resolveResult = null; } /** * A null-safe resolve. * @see #resolve */ static final JSType safeResolve( JSType type, ErrorReporter t, StaticScope<JSType> scope) { return type == null ? null : type.resolve(t, scope); } /** * Certain types have constraints on them at resolution-time. * For example, a type in an {@code @extends} annotation must be an * object. Clients should inject a validator that emits a warning * if the type does not validate, and return false. */ public boolean setValidator(Predicate<JSType> validator) { return validator.apply(this); } public static class TypePair { public final JSType typeA; public final JSType typeB; public TypePair(JSType typeA, JSType typeB) { this.typeA = typeA; this.typeB = typeB; } } /** * A hash code function for diagnosing complicated issues * around type-identity. */ public String toDebugHashCodeString() { return "{" + this.hashCode() + "}"; } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>); return informed; } private FlowScope caseInstanceOf(Node left, Node right, FlowScope blindScope, boolean outcome) { JSType leftType = getTypeIfRefinable(left, blindScope); if (leftType == null) { return blindScope; } JSType rightType = right.getJSType(); ObjectType targetType = typeRegistry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE); if (rightType instanceof FunctionType) { targetType = (FunctionType) rightType; } Visitor<JSType> visitor; if (outcome) { visitor = new RestrictByTrueInstanceOfResultVisitor(targetType); } else { visitor = new RestrictByFalseInstanceOfResultVisitor(targetType); } JSType restrictedLeftType = leftType.visit(visitor); if (restrictedLeftType != null && !restrictedLeftType.equals(leftType)) { FlowScope informed = blindScope.createChildFlowScope(); declareNameInScope(informed, left, restrictedLeftType); return informed; } return blindScope; } /** * Given 'property in object', ensures that the object has the property in the * informed scope by defining it as a qualified name if the object type lacks * the property and it's not in the blind scope. * @param object The node of the right-side of the in. * @param propertyName The string of the left-side of the in. */ private FlowScope caseIn(Node object, String propertyName, FlowScope blindScope) { JSType jsType = object.getJSType(); jsType = this.getRestrictedWithoutNull(jsType); jsType = this.getRestrictedWithoutUndefined(jsType); boolean hasProperty = false; ObjectType objectType = ObjectType.cast(jsType); if (objectType != null) { hasProperty = objectType.hasProperty(propertyName); } if (!hasProperty) { String qualifiedName = object.getQualifiedName(); if (qualifiedName != null) { String propertyQualifiedName = qualifiedName + "." + propertyName; if (blindScope.getSlot(propertyQualifiedName) == null) { FlowScope informed = blindScope.createChildFlowScope(); JSType unknownType = typeRegistry.getNativeType( JSTypeNative.UNKNOWN_TYPE); informed.inferQualifiedSlot( propertyQualifiedName, unknownType, unknownType); return informed; } } } return blindScope; } /** * @see SemanticReverseAbstractInterpreter#caseInstanceOf */ private class RestrictByTrueInstanceOfResultVisitor extends RestrictByTrueTypeOfResultVisitor { private final ObjectType target; RestrictByTrueInstanceOfResultVisitor(ObjectType target) { this.target = target; } @Override protected JSType caseTopType(JSType type) { return applyCommonRestriction(type); } @Override public JSType caseUnknownType() { if (target instanceof FunctionType) { FunctionType funcTarget = (FunctionType) target; if (funcTarget.hasInstanceType()) { return funcTarget.getInstanceType(); } } return getNativeType(UNKNOWN_TYPE); } @Override public JSType caseObjectType(ObjectType type) { return applyCommonRestriction(type); } @Override public JSType caseUnionType(UnionType type) { return applyCommonRestriction(type); } @Override public JSType caseFunctionType(FunctionType type) { return caseObjectType(type); } private JSType applyCommonRestriction(JSType type) { if (target.isUnknownType()) { return type;

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> newType != typeRegistry.getNativeType(UNKNOWN_TYPE)) { // If there are two typed declarations of the same variable, that // is an error and the second declaration is ignored, except in the // case of native types. A null input type means that the declaration // was made in TypedScopeCreator#createInitialScope and is a // native type. if (var.input == null) { n.setJSType(varType); if (parent.getType() == Token.VAR) { if (n.getFirstChild() != null) { n.getFirstChild().setJSType(varType); } } else { Preconditions.checkState(parent.getType() == Token.FUNCTION); parent.setJSType(varType); } } else { // Always warn about duplicates if the overridden type does not // match the original type. // // If the types match, suppress the warning iff there was a @suppress // tag, or if the original declaration was a stub. if (!(allowDupe || var.getParentNode().getType() == Token.EXPR_RESULT) || !newType.equals(varType)) { if (shouldReport) { compiler.report( JSError.make(sourceName, n, DUP_VAR_DECLARATION, variableName, newType.toString(), var.getInputName(), String.valueOf(var.nameNode.getLineno()), varType.toString())); } } } } } /** * Expect that all properties on interfaces that this type implements are * implemented. */ void expectAllInterfacePropertiesImplemented(FunctionType type) { ObjectType instance = type.getInstanceType(); for (ObjectType implemented : type.getAllImplementedInterfaces()) { if (implemented.getImplicitPrototype() != null) { for (String prop : implemented.getImplicitPrototype().getOwnPropertyNames()) { if (!instance.hasProperty(prop)) { Node source = type.getSource(); Preconditions.checkNotNull(source); String sourceName = (String) source.getProp(Node.SOURCENAME_PROP); sourceName = sourceName == null ? "" : sourceName; if (shouldReport) { compiler.report(JSError.make(sourceName, source, INTERFACE_METHOD_NOT_IMPLEMENTED, prop, implemented.toString(), instance.toString())); } registerMismatch(instance, implemented); } } } } } /** * Report a type mismatch */ private void mismatch(NodeTraversal t, Node n, String msg, JSType found, JSType required) { mismatch(t.getSourceName(), n, msg, found, required); } private void mismatch(NodeTraversal t, Node n, String msg, JSType found, JSTypeNative required) { mismatch(t, n, msg, found, getNativeType(required)); } private void mismatch(String sourceName, Node n, String msg, JSType found, JSType required) { registerMismatch(found, required); if (shouldReport) { compiler.report( JSError.make(sourceName, n, TYPE_MISMATCH_WARNING, formatFoundRequired(msg, found, required))); } } private void registerMismatch(JSType found, JSType required) { // Don't register a mismatch for differences in null or undefined or if the // code didn't downcast. found = found.restrictByNotNullOrUndefined(); required = required.restrictByNotNullOrUndefined(); if (found.canAssignTo(required) || required.canAssignTo(found)) { return; } mismatches.add(

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> and analyze to track // down why it happens. This is not critical and will be resolved over // time as the type checker is extended. return getNativeType(UNKNOWN_TYPE); } else { return jsType; } } private JSType getNativeType(JSTypeNative typeId) { return typeRegistry.getNativeType(typeId); } /** * Signals that the first type and the second type have been * used interchangeably. * * Type-based optimizations should take this into account * so that they don't wreck code with type warnings. */ static class TypeMismatch { final JSType typeA; final JSType typeB; /** * It's the responsibility of the class that creates the * {@code TypeMismatch} to ensure that {@code a} and {@code b} are * non-matching types. */ TypeMismatch(JSType a, JSType b) { this.typeA = a; this.typeB = b; } @Override public boolean equals(Object object) { if (object instanceof TypeMismatch) { TypeMismatch that = (TypeMismatch) object; return (that.typeA.equals(this.typeA) && that.typeB.equals(this.typeB)) || (that.typeB.equals(this.typeA) && that.typeA.equals(this.typeB)); } return false; } @Override public int hashCode() { return Objects.hashCode(typeA, typeB); } @Override public String toString() { return "(" + typeA + ", " + typeB + ")"; } } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ /** * For functions with function(this: T, ...) and T as arguments, type inference * will set the type of this on a function literal argument to the actual type * of T. * */ package com.google.javascript.rhino.jstype; public class TemplateType extends ProxyObjectType { private static final long serialVersionUID = 1L; private final String name; TemplateType(JSTypeRegistry registry, String name) { super(registry, registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE)); this.name = name; } @Override public String getReferenceName() { return name; } @Override public String toString() { return name; } @Override public boolean isTemplateType() { return true; } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import com.google.common.collect.ImmutableMap; import com.google.javascript.rhino.Node; /** * A builder for record types. * */ public class RecordTypeBuilder { private boolean isEmpty = true; private final JSTypeRegistry registry; private final ImmutableMap.Builder<String, RecordProperty> properties = ImmutableMap.builder(); public RecordTypeBuilder(JSTypeRegistry registry) { this.registry = registry; } /** * Adds a property with the given name and type to the record type. * @param name the name of the new property * @param type the JSType of the new property * @param propertyNode the node that holds this property definition * @return The builder itself for chaining purposes. */ public RecordTypeBuilder addProperty(String name, JSType type, Node propertyNode) { isEmpty = false; properties.put(name, new RecordProperty(type, propertyNode)); return this; } /** * Creates a record. * @return The record type. */ public JSType build() { // If we have an empty record, simply return the object type. if (isEmpty) { return registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE); } return registry.createRecordType(properties.build()); } static class RecordProperty { private final JSType type; private final Node propertyNode; RecordProperty(JSType type, Node propertyNode) { this.type = type; this.propertyNode = propertyNode; } public JSType getType() { return type; } public Node getPropertyNode() { return propertyNode; } } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import static com.google.javascript.rhino.jstype.TernaryValue.FALSE; import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN; /** * Boolean type. */ public class BooleanType extends ValueType { private static final long serialVersionUID = 1L; BooleanType(JSTypeRegistry registry) { super(registry); } @Override public boolean isNullable() { return false; } @Override public TernaryValue testForEquality(JSType that) { TernaryValue result = super.testForEquality(that); if (result != null) { return result; } if (that.isUnknownType() || that.isSubtype( getNativeType(JSTypeNative.NUMBER_STRING_BOOLEAN)) || that.isObject()) { return UNKNOWN; } return FALSE; } @Override public boolean isBooleanValueType() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public boolean matchesObjectContext() { // TODO(user): Revisit this for ES4, which is stricter. return true; } @Override public JSType autoboxesTo() { return getNativeType(JSTypeNative.BOOLEAN_OBJECT_TYPE); } @Override public String toString() { return getDisplayName(); } @Override public String getDisplayName() { return "boolean"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.BOTH; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseBoolean

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> MessageFormat("line {0} of {1}"); /** * Create a pass that overrides define constants. * * TODO(nicksantos): Write a builder to help JSCompiler induce * {@code replacements} from command-line flags * * @param replacements A hash table of names of defines to their replacements. * All replacements <b>must</b> be literals. */ ProcessDefines(AbstractCompiler compiler, Map<String, Node> replacements) { this.compiler = compiler; dominantReplacements = replacements; } /** * Injects a pre-computed global namespace, so that the same namespace * can be re-used for multiple check passes. Returns {@code this} for * easy chaining. */ ProcessDefines injectNamespace(GlobalNamespace namespace) { this.namespace = namespace; return this; } public void process(Node externs, Node root) { if (namespace == null) { namespace = new GlobalNamespace(compiler, root); } overrideDefines(collectDefines(root, namespace)); } private void overrideDefines(Map<String, DefineInfo> allDefines) { boolean changed = false; for (Map.Entry<String, DefineInfo> def : allDefines.entrySet()) { String defineName = def.getKey(); DefineInfo info = def.getValue(); Node inputValue = dominantReplacements.get(defineName); Node finalValue = inputValue != null ? inputValue : info.getLastValue(); if (finalValue != info.initialValue) { info.initialValueParent.replaceChild( info.initialValue, finalValue.cloneTree()); compiler.addToDebugLog("Overriding @define variable " + defineName); changed = changed || finalValue.getType() != info.initialValue.getType() || !finalValue.isEquivalentTo(info.initialValue); } } if (changed) { compiler.reportCodeChange(); } Set<String> unusedReplacements = dominantReplacements.keySet(); unusedReplacements.removeAll(allDefines.keySet()); unusedReplacements.removeAll(KNOWN_DEFINES); for (String unknownDefine : unusedReplacements) { compiler.report(JSError.make(UNKNOWN_DEFINE_WARNING, unknownDefine)); } } private static String format(MessageFormat format, Object... params) { return format.format(params); } /** * Only defines of literal number, string, or boolean are supported. */ private boolean isValidDefineType(JSTypeExpression expression) { JSType type = expression.evaluate(null, compiler.getTypeRegistry()); return !type.isUnknownType() && type.isSubtype( compiler.getTypeRegistry().getNativeType( JSTypeNative.NUMBER_STRING_BOOLEAN)); } /** * Finds all defines, and creates a {@link DefineInfo} data structure for * each one. * @return A map of {@link DefineInfo} structures, keyed by name. */ private Map<String, DefineInfo> collectDefines(Node root, GlobalNamespace namespace) { // Find all the global names with a @define annotation List<Name> allDefines = Lists.newArrayList(); for (Name name : namespace.getNameIndex().values()) { if (name.docInfo != null && name.docInfo.isDefine()) { // Process defines should not depend on check types being enabled, // so we look for the JSDoc instead of the inferred type. if (isValidDefineType(name.docInfo.getType())) { allDefines.add(name); } else { JSError error = JSError.make

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>> { static final DiagnosticType TEMPLATE_TYPE_NOT_OBJECT_TYPE = DiagnosticType.error( "JSC_TEMPLATE_TYPE_NOT_OBJECT_TYPE", "The template type must be an object type"); static final DiagnosticType TEMPLATE_TYPE_OF_THIS_EXPECTED = DiagnosticType.error( "JSC_TEMPLATE_TYPE_OF_THIS_EXPECTED", "A function type with the template type as the type of this must be a " + "parameter type"); static final DiagnosticType FUNCTION_LITERAL_UNDEFINED_THIS = DiagnosticType.warning( "JSC_FUNCTION_LITERAL_UNDEFINED_THIS", "Function literal argument refers to undefined this argument"); static final DiagnosticType FUNCTION_LITERAL_UNREAD_THIS = DiagnosticType.warning( "JSC_FUNCTION_LITERAL_UNREAD_THIS", "Function literal argument does not refer to bound this argument"); private final AbstractCompiler compiler; private final JSTypeRegistry registry; private final ReverseAbstractInterpreter reverseInterpreter; private final Scope syntacticScope; private final FlowScope functionScope; private final FlowScope bottomScope; private final Map<String, AssertionFunctionSpec> assertionFunctionsMap; /** * Local variables that do not belong to this scope, but are assigned * in this scope. */ private final Multimap<Scope, Var> assignedOuterLocalVars = HashMultimap.create(); /** * Vars that we should not map out type flow for. */ private final Set<String> unflowableVarNames = Sets.newHashSet(); TypeInference(AbstractCompiler compiler, ControlFlowGraph<Node> cfg, ReverseAbstractInterpreter reverseInterpreter, Scope functionScope, Map<String, AssertionFunctionSpec> assertionFunctionsMap) { this(compiler, cfg, reverseInterpreter, functionScope, assertionFunctionsMap, ImmutableSet.<Var>of()); } /** * @param unflowableVars Do not do infer flow on the types of these vars. * @param assertionFunctionsMap */ // TODO(nicksantos): Create a builder for this class. TypeInference(AbstractCompiler compiler, ControlFlowGraph<Node> cfg, ReverseAbstractInterpreter reverseInterpreter, Scope functionScope, Map<String, AssertionFunctionSpec> assertionFunctionsMap, Collection<Var> unflowableVars) { super(cfg, new LinkedFlowScope.FlowScopeJoinOp()); this.compiler = compiler; this.registry = compiler.getTypeRegistry(); this.reverseInterpreter = reverseInterpreter; this.syntacticScope = functionScope; this.functionScope = LinkedFlowScope.createEntryLattice(functionScope); this.assertionFunctionsMap = assertionFunctionsMap; for (Var unflowableVar : unflowableVars) { String name = unflowableVar.getName(); if (functionScope.getVar(name) == unflowableVar) { this.unflowableVarNames.add(name); } } Iterator<Var> varIt = functionScope.getVars(); while (varIt.hasNext()) { Var var = varIt.next(); if (this.unflowableVarNames.contains(var.getName())) { continue; } // For each local variable declared with the VAR keyword, the entry // type is VOID. if (var.getParentNode() != null && var.getType() == null && // no declared type var.getParentNode().getType() == Token.VAR && !var.isExtern()) { this.functionScope.inferSlotType( var.getName(), getNativeType(VOID_TYPE)); } } this.bottomScope = LinkedFlowScope.createEntryLattice(

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> case Token.MOD: case Token.BITAND: case Token.BITXOR: case Token.BITOR: case Token.MUL: case Token.SUB: case Token.DEC: case Token.INC: case Token.BITNOT: scope = traverseChildren(n, scope); n.setJSType(getNativeType(NUMBER_TYPE)); break; case Token.LP: case Token.GET_REF: scope = traverse(n.getFirstChild(), scope); n.setJSType(getJSType(n.getFirstChild())); break; case Token.COMMA: scope = traverseChildren(n, scope); n.setJSType(getJSType(n.getLastChild())); break; case Token.TYPEOF: scope = traverseChildren(n, scope); n.setJSType(getNativeType(STRING_TYPE)); break; case Token.LT: case Token.LE: case Token.GT: case Token.GE: case Token.NOT: case Token.EQ: case Token.NE: case Token.SHEQ: case Token.SHNE: case Token.INSTANCEOF: case Token.IN: scope = traverseChildren(n, scope); n.setJSType(getNativeType(BOOLEAN_TYPE)); break; case Token.GETELEM: scope = traverseGetElem(n, scope); break; case Token.EXPR_RESULT: scope = traverseChildren(n, scope); if (n.getFirstChild().getType() == Token.GETPROP) { ensurePropertyDeclared(n.getFirstChild()); } break; case Token.SWITCH: scope = traverse(n.getFirstChild(), scope); break; case Token.VAR: case Token.RETURN: case Token.THROW: scope = traverseChildren(n, scope); break; case Token.CATCH: scope = traverseCatch(n, scope); break; } if (n.getType() != Token.FUNCTION) { JSDocInfo info = n.getJSDocInfo(); if (info != null && info.hasType()) { JSType castType = info.getType().evaluate(syntacticScope, registry); // A stubbed type cast on a qualified name should take // effect for all subsequent accesses of that name, // so treat it the same as an assign to that name. if (n.isQualifiedName() && n.getParent().getType() == Token.EXPR_RESULT) { updateScopeForTypeChange(scope, n, n.getJSType(), castType); } n.setJSType(castType); } } return scope; } /** * Any value can be thrown, so it's really impossible to determine the type * of a CATCH param. Treat it as the UNKNOWN type. */ private FlowScope traverseCatch(Node n, FlowScope scope) { Node name = n.getFirstChild(); JSType type = getNativeType(JSTypeNative.UNKNOWN_TYPE); name.setJSType(type); redeclare(scope, name.getString(), type); return scope; } private FlowScope traverseAssign(Node n, FlowScope scope) { Node left = n.getFirstChild(); Node right = n.getLastChild(); scope = traverseChildren(n, scope); JSType leftType = left.getJSType(); JSType rightType = getJSType(right); n.setJSType(rightType); updateScopeForTypeChange(scope, left, leftType, rightType); return scope; } /** * Updates the scope

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> according to the result of a type change, like * an assignment or a type cast. */ private void updateScopeForTypeChange( FlowScope scope, Node left, JSType leftType, JSType resultType) { Preconditions.checkNotNull(resultType); switch (left.getType()) { case Token.NAME: String varName = left.getString(); Var var = syntacticScope.getVar(varName); if (var != null && var.isLocal() && var.getScope() != syntacticScope) { assignedOuterLocalVars.put(var.getScope(), var); } // When looking at VAR initializers for declared VARs, we trust // the declared type over the type it's being initialized to. // This has two purposes: // 1) We avoid re-declaring declared variables so that built-in // types defined in externs are not redeclared. // 2) When there's a lexical closure like // /** @type {?string} */ var x = null; // function f() { x = 'xyz'; } // the inference will ignore the lexical closure, // which is just wrong. This bug needs to be fixed eventually. boolean isVarDeclaration = left.hasChildren(); if (!isVarDeclaration || var == null || var.isTypeInferred()) { redeclare(scope, varName, resultType); } left.setJSType(isVarDeclaration || leftType == null ? resultType : null); if (var != null && var.isTypeInferred()) { JSType oldType = var.getType(); var.setType(oldType == null ? resultType : oldType.getLeastSupertype(resultType)); } break; case Token.GETPROP: String qualifiedName = left.getQualifiedName(); if (qualifiedName != null) { scope.inferQualifiedSlot(qualifiedName, leftType == null ? getNativeType(UNKNOWN_TYPE) : leftType, resultType); } left.setJSType(resultType); ensurePropertyDefined(left, resultType); break; } } /** * Defines a property if the property has not been defined yet. */ private void ensurePropertyDefined(Node getprop, JSType rightType) { String propName = getprop.getLastChild().getString(); JSType nodeType = getJSType(getprop.getFirstChild()); ObjectType objectType = ObjectType.cast( nodeType.restrictByNotNullOrUndefined()); if (objectType == null) { registry.registerPropertyOnType(propName, nodeType); } else { if (ensurePropertyDeclaredHelper(getprop, objectType)) { return; } if (!objectType.isPropertyTypeDeclared(propName)) { // We do not want a "stray" assign to define an inferred property // for every object of this type in the program. So we use a heuristic // approach to determine whether to infer the propery. // // 1) If the property is already defined, join it with the previously // inferred type. // 2) If this isn't an instance object, define it. // 3) If the property of an object is being assigned in the constructor, // define it. // 4) If this is a stub, define it. // 5) Otherwise, do not define the type, but declare it in the registry // so that we can use it for missing property checks. if (objectType.hasProperty(propName) || !objectType.isInstanceType()) { if ("prototype".equals(propName)) {

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> objectType.defineDeclaredProperty(propName, rightType, false, getprop); } else { objectType.defineInferredProperty(propName, rightType, false, getprop); } } else { if (getprop.getFirstChild().getType() == Token.THIS && getJSType(syntacticScope.getRootNode()).isConstructor()) { objectType.defineInferredProperty(propName, rightType, false, getprop); } else { registry.registerPropertyOnType(propName, objectType); } } } } } /** * Defines a declared property if it has not been defined yet. * * This handles the case where a property is declared on an object where * the object type is inferred, and so the object type will not * be known in {@code TypedScopeCreator}. */ private void ensurePropertyDeclared(Node getprop) { ObjectType ownerType = ObjectType.cast( getJSType(getprop.getFirstChild()).restrictByNotNullOrUndefined()); if (ownerType != null) { ensurePropertyDeclaredHelper(getprop, ownerType); } } /** * Declares a property on its owner, if necessary. * @return True if a property was declared. */ private boolean ensurePropertyDeclaredHelper( Node getprop, ObjectType objectType) { String propName = getprop.getLastChild().getString(); String qName = getprop.getQualifiedName(); if (qName != null) { Var var = syntacticScope.getVar(qName); if (var != null && !var.isTypeInferred()) { // Handle normal declarations that could not be addressed earlier. if (propName.equals("prototype") || // Handle prototype declarations that could not be addressed earlier. (!objectType.hasOwnProperty(propName) && (!objectType.isInstanceType() || (var.isExtern() && !objectType.isNativeObjectType())))) { return objectType.defineDeclaredProperty( propName, var.getType(), var.isExtern(), getprop); } } } return false; } private FlowScope traverseName(Node n, FlowScope scope) { String varName = n.getString(); Node value = n.getFirstChild(); JSType type = n.getJSType(); if (value != null) { scope = traverse(value, scope); updateScopeForTypeChange(scope, n, n.getJSType() /* could be null */, getJSType(value)); return scope; } else { StaticSlot<JSType> var = scope.getSlot(varName); if (var != null) { // There are two situations where we don't want to use type information // from the scope, even if we have it. // 1) The var is escaped in a weird way, e.g., // function f() { var x = 3; function g() { x = null } (x); } boolean isInferred = var.isTypeInferred(); boolean unflowable = isInferred && unflowableVarNames.contains(varName); // 2) We're reading type information from another scope for an // inferred variable. // var t = null; function f() { (t); } boolean nonLocalInferredSlot = isInferred && syntacticScope.getParent() != null && var == syntacticScope.getParent().getSlot(varName); if (!unflowable && !nonLocalInferredSlot) { type = var.getType(); if (type == null) { type = getNativeType(UNKNOWN_TYPE); } } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> } n.setJSType(type); return scope; } /** Traverse each element of the array. */ private FlowScope traverseArrayLiteral(Node n, FlowScope scope) { scope = traverseChildren(n, scope); n.setJSType(getNativeType(ARRAY_TYPE)); return scope; } private FlowScope traverseObjectLiteral(Node n, FlowScope scope) { JSType type = n.getJSType(); Preconditions.checkNotNull(type); for (Node name = n.getFirstChild(); name != null; name = name.getNext()) { scope = traverse(name.getFirstChild(), scope); } // Object literals can be reflected on other types, or changed with // type casts. // See CodingConvention#getObjectLiteralCase and goog.object.reflect. // Ignore these types of literals. // TODO(nicksantos): There should be an "anonymous object" type that // we can check for here. ObjectType objectType = ObjectType.cast(type); if (objectType == null) { return scope; } boolean hasLendsName = n.getJSDocInfo() != null && n.getJSDocInfo().getLendsName() != null; if (objectType.hasReferenceName() && !hasLendsName) { return scope; } for (Node name = n.getFirstChild(); name != null; name = name.getNext()) { Node value = name.getFirstChild(); String memberName = NodeUtil.getObjectLitKeyName(name); if (memberName != null) { JSType rawValueType = name.getFirstChild().getJSType(); JSType valueType = NodeUtil.getObjectLitKeyTypeFromValueType( name, rawValueType); if (valueType == null) { valueType = getNativeType(UNKNOWN_TYPE); } objectType.defineInferredProperty(memberName, valueType, false, name); } else { n.setJSType(getNativeType(UNKNOWN_TYPE)); } } return scope; } private FlowScope traverseAdd(Node n, FlowScope scope) { Node left = n.getFirstChild(); Node right = left.getNext(); scope = traverseChildren(n, scope); JSType leftType = left.getJSType(); JSType rightType = right.getJSType(); JSType type = getNativeType(UNKNOWN_TYPE); if (leftType != null && rightType != null) { boolean leftIsUnknown = leftType.isUnknownType(); boolean rightIsUnknown = rightType.isUnknownType(); if (leftIsUnknown && rightIsUnknown) { type = getNativeType(UNKNOWN_TYPE); } else if ((!leftIsUnknown && leftType.isString()) || (!rightIsUnknown && rightType.isString())) { type = getNativeType(STRING_TYPE); } else if (leftIsUnknown || rightIsUnknown) { type = getNativeType(UNKNOWN_TYPE); } else if (isAddedAsNumber(leftType) && isAddedAsNumber(rightType)) { type = getNativeType(NUMBER_TYPE); } else { type = registry.createUnionType(STRING_TYPE, NUMBER_TYPE); } } n.setJSType(type); if (n.getType() == Token.ASSIGN_ADD) { updateScopeForTypeChange(scope, left, leftType, type); } return scope; } private boolean isAddedAsNumber(JSType type) { return type.isSubtype(registry.createUnionType(VOID_TYPE, NULL_TYPE, NUMBER_VALUE_OR

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>_OBJECT_TYPE, BOOLEAN_TYPE, BOOLEAN_OBJECT_TYPE)); } private FlowScope traverseHook(Node n, FlowScope scope) { Node condition = n.getFirstChild(); Node trueNode = condition.getNext(); Node falseNode = n.getLastChild(); // verify the condition scope = traverse(condition, scope); // reverse abstract interpret the condition to produce two new scopes FlowScope trueScope = reverseInterpreter. getPreciserScopeKnowingConditionOutcome( condition, scope, true); FlowScope falseScope = reverseInterpreter. getPreciserScopeKnowingConditionOutcome( condition, scope, false); // traverse the true node with the trueScope traverse(trueNode, trueScope.createChildFlowScope()); // traverse the false node with the falseScope traverse(falseNode, falseScope.createChildFlowScope()); // meet true and false nodes' types and assign JSType trueType = trueNode.getJSType(); JSType falseType = falseNode.getJSType(); if (trueType != null && falseType != null) { n.setJSType(trueType.getLeastSupertype(falseType)); } else { n.setJSType(null); } return scope.createChildFlowScope(); } private FlowScope traverseCall(Node n, FlowScope scope) { scope = traverseChildren(n, scope); Node left = n.getFirstChild(); JSType functionType = getJSType(left).restrictByNotNullOrUndefined(); if (functionType != null) { if (functionType instanceof FunctionType) { FunctionType fnType = (FunctionType) functionType; n.setJSType(fnType.getReturnType()); updateTypeOfParametersOnClosure(n, fnType); updateTypeOfThisOnClosure(n, fnType); } else if (functionType.equals(getNativeType(CHECKED_UNKNOWN_TYPE))) { n.setJSType(getNativeType(CHECKED_UNKNOWN_TYPE)); } } scope = tightenTypesAfterAssertions(scope, n); return scope; } private FlowScope tightenTypesAfterAssertions(FlowScope scope, Node callNode) { Node left = callNode.getFirstChild(); Node firstParam = left.getNext(); AssertionFunctionSpec assertionFunctionSpec = assertionFunctionsMap.get(left.getQualifiedName()); if (assertionFunctionSpec == null || firstParam == null) { return scope; } Node assertedNode = assertionFunctionSpec.getAssertedParam(firstParam); if (assertedNode == null) { return scope; } JSTypeNative assertedType = assertionFunctionSpec.getAssertedType(); String assertedNodeName = assertedNode.getQualifiedName(); // Handle assertions that enforce expressions evaluate to true. if (assertedType == null) { if (assertedNodeName != null) { JSType type = getJSType(assertedNode); JSType narrowed = type.restrictByNotNullOrUndefined(); if (type != narrowed) { scope = scope.createChildFlowScope(); redeclare(scope, assertedNodeName, narrowed); callNode.setJSType(narrowed); } } else if (assertedNode.getType() == Token.AND || assertedNode.getType() == Token.OR) { BooleanOutcomePair conditionOutcomes = traverseWithinShortCircuitingBinOp(assertedNode, scope); scope = reverseInterpreter.getPreciserScopeKnowingConditionOutcome( assertedNode, conditionOutcomes.getOutcomeFlowScope( assertedNode.getType(), true), true); } } else if (assert

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> (jArgument.getType() == Token.FUNCTION && jArgumentType instanceof FunctionType) { if (iArgumentType != null && // null and undefined get filtered out above. !iArgumentType.isNoType()) { // If it's an function expression, update the type of this // using the actual type of T. FunctionType jArgumentFnType = (FunctionType) jArgumentType; if (jArgumentFnType.getTypeOfThis().isUnknownType()) { // The new type will be picked up when we traverse the inner // function. jArgument.setJSType( registry.createFunctionTypeWithNewThisType( jArgumentFnType, (ObjectType) iArgumentType)); } // Warn if the anonymous function literal does not reference this. if (!NodeUtil.referencesThis( NodeUtil.getFunctionBody(jArgument))) { compiler.report(JSError.make(NodeUtil.getSourceName(n), n, FUNCTION_LITERAL_UNREAD_THIS)); } } else { // Warn if the anonymous function literal references this. if (NodeUtil.referencesThis( NodeUtil.getFunctionBody(jArgument))) { compiler.report(JSError.make(NodeUtil.getSourceName(n), n, FUNCTION_LITERAL_UNDEFINED_THIS)); } } } // TODO(user): Add code to TypeCheck to check that the // types of the arguments match. } } j++; } if (!foundTemplateTypeOfThisParameter) { compiler.report(JSError.make(NodeUtil.getSourceName(n), n, TEMPLATE_TYPE_OF_THIS_EXPECTED)); return; } } i++; } } private FlowScope traverseNew(Node n, FlowScope scope) { Node constructor = n.getFirstChild(); scope = traverse(constructor, scope); JSType constructorType = constructor.getJSType(); JSType type = null; if (constructorType != null) { constructorType = constructorType.restrictByNotNullOrUndefined(); if (constructorType.isUnknownType()) { type = getNativeType(UNKNOWN_TYPE); } else if (constructorType instanceof FunctionType) { FunctionType ct = (FunctionType) constructorType; if (ct.isConstructor()) { type = ct.getInstanceType(); } } } n.setJSType(type); for (Node arg = constructor.getNext(); arg != null; arg = arg.getNext()) { scope = traverse(arg, scope); } return scope; } private BooleanOutcomePair traverseAnd(Node n, FlowScope scope) { return traverseShortCircuitingBinOp(n, scope, true); } private FlowScope traverseChildren(Node n, FlowScope scope) { for (Node el = n.getFirstChild(); el != null; el = el.getNext()) { scope = traverse(el, scope); } return scope; } private FlowScope traverseGetElem(Node n, FlowScope scope) { scope = traverseChildren(n, scope); ObjectType objType = ObjectType.cast( getJSType(n.getFirstChild()).restrictByNotNullOrUndefined()); if (objType != null) { JSType type = objType.getParameterType(); if (type != null) { n.setJSType(type); } } return dereferencePointer(n.getFirstChild(), scope); } private FlowScope traverseGetProp(Node n, FlowScope scope) { Node objNode = n.getFirstChild(); Node property = n.getLastChild(); scope = traverseChildren(n, scope); n.set

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>JSType( getPropertyType( objNode.getJSType(), property.getString(), n, scope)); return dereferencePointer(n.getFirstChild(), scope); } /** * If we access a property of a symbol, then that symbol is not * null or undefined. */ private FlowScope dereferencePointer(Node n, FlowScope scope) { if (n.getType() == Token.NAME) { JSType type = getJSType(n); JSType narrowed = type.restrictByNotNullOrUndefined(); if (type != narrowed) { scope = scope.createChildFlowScope(); redeclare(scope, n.getString(), narrowed); } } return scope; } private JSType getPropertyType(JSType objType, String propName, Node n, FlowScope scope) { // Scopes sometimes contain inferred type info about qualified names. String qualifiedName = n.getQualifiedName(); StaticSlot<JSType> var = scope.getSlot(qualifiedName); if (var != null) { JSType varType = var.getType(); if (varType != null) { if (varType.equals(getNativeType(UNKNOWN_TYPE)) && var != syntacticScope.getSlot(qualifiedName)) { // If the type of this qualified name has been checked in this scope, // then use CHECKED_UNKNOWN_TYPE instead to indicate that. return getNativeType(CHECKED_UNKNOWN_TYPE); } else { return varType; } } } JSType propertyType = null; if (objType != null) { propertyType = objType.findPropertyType(propName); } if ((propertyType == null || propertyType.isUnknownType()) && qualifiedName != null) { // If we find this node in the registry, then we can infer its type. ObjectType regType = ObjectType.cast(registry.getType(qualifiedName)); if (regType != null) { propertyType = regType.getConstructor(); } } return propertyType; } private BooleanOutcomePair traverseOr(Node n, FlowScope scope) { return traverseShortCircuitingBinOp(n, scope, false); } private BooleanOutcomePair traverseShortCircuitingBinOp( Node n, FlowScope scope, boolean condition) { Node left = n.getFirstChild(); Node right = n.getLastChild(); // type the left node BooleanOutcomePair leftLiterals = traverseWithinShortCircuitingBinOp(left, scope.createChildFlowScope()); JSType leftType = left.getJSType(); // reverse abstract interpret the left node to produce the correct // scope in which to verify the right node FlowScope rightScope = reverseInterpreter. getPreciserScopeKnowingConditionOutcome( left, leftLiterals.getOutcomeFlowScope(left.getType(), condition), condition); // type the right node BooleanOutcomePair rightLiterals = traverseWithinShortCircuitingBinOp( right, rightScope.createChildFlowScope()); JSType rightType = right.getJSType(); JSType type; BooleanOutcomePair literals; if (leftType != null && rightType != null) { leftType = leftType.getRestrictedTypeGivenToBooleanOutcome(!condition); if (leftLiterals.toBooleanOutcomes == BooleanLiteralSet.get(!condition)) { // Use the restricted left type, since the right side never gets // evaluated. type = leftType; literals = leftLiterals; } else { // Use the join of the restricted left type knowing the outcome of the // ToBoolean predicate and of the right type

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> FlowScope leftScope, FlowScope rightScope) { this.toBooleanOutcomes = toBooleanOutcomes; this.booleanValues = booleanValues; this.leftScope = leftScope; this.rightScope = rightScope; } /** * Gets the safe estimated scope without knowing if all of the subexpressions * will be evaluated. */ FlowScope getJoinedFlowScope() { if (joinedScope == null) { if (leftScope == rightScope) { joinedScope = rightScope; } else { joinedScope = join(leftScope, rightScope); } } return joinedScope; } /** * Gets the outcome scope if we do know the outcome of the entire * expression. */ FlowScope getOutcomeFlowScope(int nodeType, boolean outcome) { if (nodeType == Token.AND && outcome || nodeType == Token.OR && !outcome) { // We know that the whole expression must have executed. return rightScope; } else { return getJoinedFlowScope(); } } } private BooleanOutcomePair newBooleanOutcomePair( JSType jsType, FlowScope flowScope) { if (jsType == null) { return new BooleanOutcomePair( BooleanLiteralSet.BOTH, BooleanLiteralSet.BOTH, flowScope, flowScope); } return new BooleanOutcomePair(jsType.getPossibleToBooleanOutcomes(), registry.getNativeType(BOOLEAN_TYPE).isSubtype(jsType) ? BooleanLiteralSet.BOTH : BooleanLiteralSet.EMPTY, flowScope, flowScope); } private void redeclare(FlowScope scope, String varName, JSType varType) { if (varType == null) { varType = getNativeType(JSTypeNative.UNKNOWN_TYPE); } if (unflowableVarNames.contains(varName)) { return; } scope.inferSlotType(varName, varType); } /** * This method gets the JSType from the Node argument and verifies that it is * present. */ private JSType getJSType(Node n) { JSType jsType = n.getJSType(); if (jsType == null) { // TODO(nicksantos): This branch indicates a compiler bug, not worthy of // halting the compilation but we should log this and analyze to track // down why it happens. This is not critical and will be resolved over // time as the type checker is extended. return getNativeType(UNKNOWN_TYPE); } else { return jsType; } } private JSType getNativeType(JSTypeNative typeId) { return registry.getNativeType(typeId); } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import static com.google.javascript.rhino.jstype.TernaryValue.FALSE; import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN; /** * String type. */ public final class StringType extends ValueType { private static final long serialVersionUID = 1L; StringType(JSTypeRegistry registry) { super(registry); } @Override public TernaryValue testForEquality(JSType that) { TernaryValue result = super.testForEquality(that); if (result != null) { return result; } if (that.isUnknownType() || that.isSubtype( getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN))) { return UNKNOWN; } return FALSE; } @Override public boolean isStringValueType() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public boolean matchesObjectContext() { // TODO(user): Revisit this for ES4, which is stricter. return true; } @Override public String toString() { return getDisplayName(); } @Override public String getDisplayName() { return "string"; } @Override public JSType autoboxesTo() { return getNativeType(JSTypeNative.STRING_OBJECT_TYPE); } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.BOTH; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseStringType(); } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> JSType evaluate(StaticScope<JSType> scope, JSTypeRegistry registry) { return registry.createFromTypeNodes(root, sourceName, scope, root.getBooleanProp(Node.BRACELESS_TYPE)); } @Override public boolean equals(Object other) { return other instanceof JSTypeExpression && ((JSTypeExpression) other).root.checkTreeEqualsSilent(root); } @Override public int hashCode() { return root.toStringTree().hashCode(); } Node getRoot() { return root; } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Nick Santos * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import com.google.javascript.rhino.testing.BaseJSTypeTestCase; /** * Tests for FunctionTypes. * @author nicksantos@google.com (Nick Santos) */ public class FunctionTypeTest extends BaseJSTypeTestCase { public void testDefaultReturnType() { FunctionType f = new FunctionBuilder(registry).build(); assertEquals(UNKNOWN_TYPE, f.getReturnType()); } public void testSupAndInfOfReturnTypes() { FunctionType retString = new FunctionBuilder(registry) .withParamsNode(registry.createParameters()) .withInferredReturnType(STRING_TYPE).build(); FunctionType retNumber = new FunctionBuilder(registry) .withParamsNode(registry.createParameters()) .withReturnType(NUMBER_TYPE).build(); assertLeastSupertype( "function (): (number|string)", retString, retNumber); assertGreatestSubtype( "function (): None", retString, retNumber); assertTrue(retString.isReturnTypeInferred()); assertFalse(retNumber.isReturnTypeInferred()); assertTrue( ((FunctionType) retString.getLeastSupertype(retNumber)) .isReturnTypeInferred()); assertTrue( ((FunctionType) retString.getGreatestSubtype(retString)) .isReturnTypeInferred()); } public void testSupAndInfOfReturnTypesWithDifferentParams() { FunctionType retString = new FunctionBuilder(registry) .withParamsNode(registry.createParameters(NUMBER_TYPE)) .withInferredReturnType(STRING_TYPE).build(); FunctionType retNumber = new FunctionBuilder(registry) .withParamsNode(registry.createParameters()) .withReturnType(NUMBER_TYPE).build(); assertLeastSupertype( "Function", retString, retNumber); assertGreatestSubtype( "function

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> (...[*]): None", retString, retNumber); } public void testSupAndInfWithDifferentParams() { FunctionType retString = new FunctionBuilder(registry) .withParamsNode(registry.createParameters(NUMBER_TYPE)) .withReturnType(STRING_TYPE).build(); FunctionType retNumber = new FunctionBuilder(registry) .withParamsNode(registry.createParameters(STRING_TYPE)) .withReturnType(NUMBER_TYPE).build(); assertLeastSupertype( "Function", retString, retNumber); assertGreatestSubtype( "function (...[*]): None", retString, retNumber); } public void testSupAndInfWithDifferentThisTypes() { FunctionType retString = new FunctionBuilder(registry) .withParamsNode(registry.createParameters()) .withTypeOfThis(OBJECT_TYPE) .withReturnType(STRING_TYPE).build(); FunctionType retNumber = new FunctionBuilder(registry) .withParamsNode(registry.createParameters()) .withTypeOfThis(DATE_TYPE) .withReturnType(NUMBER_TYPE).build(); assertLeastSupertype( "function (this:Object): (number|string)", retString, retNumber); assertGreatestSubtype( "function (this:Date): None", retString, retNumber); } public void testSupAndInfWithDifferentThisTypes2() { FunctionType retString = new FunctionBuilder(registry) .withParamsNode(registry.createParameters()) .withTypeOfThis(ARRAY_TYPE) .withReturnType(STRING_TYPE).build(); FunctionType retNumber = new FunctionBuilder(registry) .withParamsNode(registry.createParameters()) .withTypeOfThis(DATE_TYPE) .withReturnType(NUMBER_TYPE).build(); assertLeastSupertype( "function (this:Object): (number|string)", retString, retNumber); assertGreatestSubtype( "function (this:NoObject): None", retString, retNumber); } public void testSupAndInfOfReturnTypesWithNumOfParams() { FunctionType twoNumbers = new FunctionBuilder(registry) .withParamsNode(registry.createParameters(NUMBER_TYPE, NUMBER_TYPE)) .withReturnType(BOOLEAN_TYPE).build(); FunctionType oneNumber = new FunctionBuilder(registry) .withParamsNode(registry.createParameters(NUMBER_TYPE)) .withReturnType(BOOLEAN_TYPE).build(); assertLeastSupertype( "Function", twoNumbers, oneNumber); assertGreatestSubtype( "function (...[*]): None", twoNumbers, oneNumber); } public void testSubtypeWithInterfaceThisType() { FunctionType iface = registry.createInterfaceType("I", null); FunctionType ifaceReturnBoolean = new FunctionBuilder(registry) .withParamsNode(registry.createParameters()) .withTypeOfThis(iface.getInstanceType()) .withReturnType(BOOLEAN_TYPE).build(); FunctionType objReturnBoolean = new FunctionBuilder(registry) .withParamsNode(registry.createParameters()) .withTypeOfThis(OBJECT_TYPE) .withReturnType(BOOLEAN_TYPE).build(); assertTrue(objReturnBoolean.canAssignTo(ifaceReturnBoolean)); } public void testCtorWithPrototypeSet() { FunctionType ctor = registry.createConstructorType( "Foo", null, null, null); assertFalse(ctor.getInstanceType().isUnknownType()); ctor.defineDeclaredProperty("prototype", UNKNOWN_TYPE, false, null); assertTrue(ctor.getInstanceType().isUnknownType()); } public void testEmptyFunctionTypes() { assertTrue(LEAST_FUNCTION_TYPE.isEmptyType()); assertFalse(GREATEST_FUNCTION_

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; /** * An object type with a declared default index type. * * For example, <code>Object.<number, string></code> can take only numbers as * keys. * */ final class IndexedType extends ProxyObjectType { private static final long serialVersionUID = 1L; final JSType indexType; IndexedType( JSTypeRegistry registry, ObjectType objectType, JSType indexType) { super(registry, objectType); this.indexType = indexType; } @Override public JSType getIndexType() { return indexType; } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import com.google.javascript.rhino.Node; /** * A builder class for function and arrow types. * * If you need to build an interface constructor, * use {@link JSTypeRegistry#createInterfaceType}. * * @author nicksantos@google.com (Nick Santos) */ public final class FunctionBuilder { private final JSTypeRegistry registry; private String name = null; private Node sourceNode = null; private Node parametersNode = null; private JSType returnType = null; private ObjectType typeOfThis = null; private String templateTypeName = null; private boolean inferredReturnType = false; private boolean isConstructor = false; private boolean isNativeType = false; public FunctionBuilder(JSTypeRegistry registry) { this.registry = registry; } /** Set the name of the function type. */ public FunctionBuilder withName(String name) { this.name = name; return this; } /** Set the source node of the function type. */ public FunctionBuilder withSourceNode(Node sourceNode) { this.sourceNode = sourceNode; return this; } /** Set the parameters of the function type from a FunctionParamBuilder. */ public FunctionBuilder withParams(FunctionParamBuilder params) { this.parametersNode = params.build(); return this; } /** * Set the parameters of the function type with a specially-formatted node. */ public FunctionBuilder withParamsNode(Node parametersNode) { this.parametersNode = parametersNode; return this; } /** Set the return type. */ public FunctionBuilder withReturnType(JSType returnType) { this.returnType = returnType; return this; } /** Set the return type and whether it's inferred. */

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> public FunctionBuilder withReturnType(JSType returnType, boolean inferred) { this.returnType = returnType; this.inferredReturnType = inferred; return this; } /** Sets an inferred return type. */ public FunctionBuilder withInferredReturnType(JSType returnType) { this.returnType = returnType; this.inferredReturnType = true; return this; } /** Set the "this" type. */ public FunctionBuilder withTypeOfThis(ObjectType typeOfThis) { this.typeOfThis = typeOfThis; return this; } /** Set the template name. */ public FunctionBuilder withTemplateName(String templateTypeName) { this.templateTypeName = templateTypeName; return this; } /** Make this a constructor. */ public FunctionBuilder forConstructor() { this.isConstructor = true; return this; } /** Set whether this is a constructor. */ public FunctionBuilder setIsConstructor(boolean isConstructor) { this.isConstructor = isConstructor; return this; } /** Make this a native type. */ FunctionBuilder forNativeType() { this.isNativeType = true; return this; } /** Copies all the information from another function type. */ public FunctionBuilder copyFromOtherFunction(FunctionType otherType) { this.name = otherType.getReferenceName(); this.sourceNode = otherType.getSource(); this.parametersNode = otherType.getParametersNode(); this.returnType = otherType.getReturnType(); this.typeOfThis = otherType.getTypeOfThis(); this.templateTypeName = otherType.getTemplateTypeName(); this.isConstructor = otherType.isConstructor(); this.isNativeType = otherType.isNativeObjectType(); return this; } /** Construct a new function type. */ public FunctionType build() { return new FunctionType(registry, name, sourceNode, new ArrowType(registry, parametersNode, returnType, inferredReturnType), typeOfThis, templateTypeName, isConstructor, isNativeType); } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN; import com.google.javascript.rhino.ErrorReporter; import com.google.javascript.rhino.Node; import java.util.Set; /** * The {@code Unknown} type. */ public class UnknownType extends ObjectType { private static final long serialVersionUID = 1L; // See the explanation of checked unknown types in JSTypeNative. private final boolean isChecked; UnknownType(JSTypeRegistry registry, boolean isChecked) { super(registry); this.isChecked = isChecked; } @Override public boolean isUnknownType() { return true; } @Override public boolean isCheckedUnknownType() { return isChecked; } @Override public boolean canAssignTo(JSType that) { return true; } @Override public boolean canBeCalled() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesObjectContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public TernaryValue testForEquality(JSType that) { return UNKNOWN; } @Override public boolean isNullable() { return true; } @Override public boolean isSubtype(JSType that) { return true; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseUnknownType(); } @Override public String toString() { return getReferenceName(); } @Override boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns, Node propertyNode)

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Nick Santos * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import com.google.common.base.Preconditions; import com.google.javascript.rhino.ErrorReporter; import com.google.javascript.rhino.Node; /** * An {@code UnresolvedType} is a reference to some type expression. * This provides a convenient mechanism for implementing forward * references to types; a {@code UnresolvedType} can be used as a * placeholder until its reference is resolved. * * The {@code UnresolvedType} will behave like an opaque unknown type. * When its {@code #resolve} method is called, it will return the underlying * type. The underlying type can resolve to any JS type.<p> * * @author nicksantos@google.com (Nick Santos) */ class UnresolvedTypeExpression extends UnknownType { private static final long serialVersionUID = 1L; private final Node typeExpr; private final String sourceName; /** * If true, don't warn about unresolveable type names. * * NOTE(nicksantos): A lot of third-party code doesn't use our type syntax. * They have code like * {@code @return} the bus. * and they clearly don't mean that "the" is a type. In these cases, we're * forgiving and try to guess whether or not "the" is a type when it's not * clear. */ private boolean forgiving = false; /** * Create a named type based on the reference. */ UnresolvedTypeExpression(JSTypeRegistry registry, Node typeExpr, String sourceName, boolean forgiving) { super(registry, false); Preconditions.checkNotNull(typeExpr); this.typeExpr = typeExpr; this.sourceName = sourceName;

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> this.forgiving = forgiving; } /** * Resolve the referenced type within the enclosing scope. */ @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> enclosing) { return registry.createFromTypeNodes(typeExpr, sourceName, enclosing, forgiving); } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import static com.google.javascript.rhino.jstype.TernaryValue.FALSE; import static com.google.javascript.rhino.jstype.TernaryValue.TRUE; import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN; /** * Void type whose only element is the {@code undefined} value. */ public class VoidType extends ValueType { private static final long serialVersionUID = 1L; VoidType(JSTypeRegistry registry) { super(registry); } @Override public JSType restrictByNotNullOrUndefined() { return registry.getNativeType(JSTypeNative.NO_TYPE); } @Override public TernaryValue testForEquality(JSType that) { if (UNKNOWN.equals(super.testForEquality(that))) { return UNKNOWN; } if (that.isSubtype(this) || that.isSubtype(getNativeType(JSTypeNative.NULL_TYPE))) { return TRUE; } return FALSE; } @Override public boolean matchesNumberContext() { return false; } @Override public boolean matchesObjectContext() { return false; } @Override public boolean matchesStringContext() { return true; } @Override public boolean isVoidType() { return true; } @Override public String toString() { return getDisplayName(); } @Override public String getDisplayName() { return "undefined"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.FALSE; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseVoidType(); } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> summarized by the * following table: * <table> * <tr><th>type</th><th>result</th></tr> * <tr><td>{@code undefined}</td><td>"undefined"</td></tr> * <tr><td>{@code null}</td><td>"object"</td></tr> * <tr><td>{@code boolean}</td><td>"boolean"</td></tr> * <tr><td>{@code number}</td><td>"number"</td></tr> * <tr><td>{@code string}</td><td>"string"</td></tr> * <tr><td>{@code Object} (which doesn't implement [[Call]])</td> * <td>"object"</td></tr> * <tr><td>{@code Object} (which implements [[Call]])</td> * <td>"function"</td></tr> * </table> * @param type the type to restrict * @param value A value known to be equal or not equal to the result of the * {@code typeof} operation * @param resultEqualsValue {@code true} if the {@code typeOf} result is known * to equal {@code value}; {@code false} if it is known <em>not</em> to * equal {@code value} * @return the restricted type or null if no version of the type matches the * restriction */ JSType getRestrictedByTypeOfResult(JSType type, String value, boolean resultEqualsValue) { if (type == null) { if (resultEqualsValue) { JSType result = getNativeTypeForTypeOf(value); return result == null ? getNativeType(UNKNOWN_TYPE) : result; } else { return null; } } return type.visit( new RestrictByOneTypeOfResultVisitor(value, resultEqualsValue)); } JSType getNativeType(JSTypeNative typeId) { return typeRegistry.getNativeType(typeId); } /** * If we definitely know what a type is based on the typeof result, * return it. Otherwise, return null. * * The typeof operation in JS is poorly defined, and this function works * for both the native typeof and goog.typeOf. It should not be made public, * because its semantics are informally defined, and would be wrong in * the general case. */ private JSType getNativeTypeForTypeOf(String value) { if (value.equals("number")) { return getNativeType(NUMBER_TYPE); } else if (value.equals("boolean")) { return getNativeType(BOOLEAN_TYPE); } else if (value.equals("string")) { return getNativeType(STRING_TYPE); } else if (value.equals("undefined")) { return getNativeType(VOID_TYPE); } else if (value.equals("function")) { return getNativeType(U2U_CONSTRUCTOR_TYPE); } else { return null; } } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> type.isEnumType() predicate. Currently, not all enum types are // implemented by the EnumClass, e.g. the unknown type and the any // type. The types need to be defined by interfaces such that an // implementation can implement multiple types interface. EnumType valueEnumType = (EnumType) value.getJSType(); JSType valueEnumPrimitiveType = valueEnumType.getElementsType().getPrimitiveType(); validator.expectCanAssignTo(t, value, valueEnumPrimitiveType, primitiveType, "incompatible enum element types"); } else { // The error condition is handled in TypedScopeCreator. } } /** * This predicate is used to determine if the node represents an expression * that is a Reference according to JavaScript definitions. * * @param n The node being checked. * @return true if the sub-tree n is a reference, false otherwise. */ private static boolean isReference(Node n) { switch (n.getType()) { case Token.GETELEM: case Token.GETPROP: case Token.NAME: return true; default: return false; } } /** * This method gets the JSType from the Node argument and verifies that it is * present. */ private JSType getJSType(Node n) { JSType jsType = n.getJSType(); if (jsType == null) { // TODO(nicksantos): This branch indicates a compiler bug, not worthy of // halting the compilation but we should log this and analyze to track // down why it happens. This is not critical and will be resolved over // time as the type checker is extended. return getNativeType(UNKNOWN_TYPE); } else { return jsType; } } /** * Gets the type of the node or {@code null} if the node's type is not a * function. */ private FunctionType getFunctionType(Node n) { JSType type = getJSType(n).restrictByNotNullOrUndefined(); if (type.isUnknownType()) { return typeRegistry.getNativeFunctionType(U2U_CONSTRUCTOR_TYPE); } else if (type instanceof FunctionType) { return (FunctionType) type; } else { return null; } } // TODO(nicksantos): TypeCheck should never be attaching types to nodes. // All types should be attached by TypeInference. This is not true today // for legacy reasons. There are a number of places where TypeInference // doesn't attach a type, as a signal to TypeCheck that it needs to check // that node's type. /** * Ensure that the given node has a type. If it does not have one, * attach the UNKNOWN_TYPE. */ private void ensureTyped(NodeTraversal t, Node n) { ensureTyped(t, n, getNativeType(UNKNOWN_TYPE)); } private void ensureTyped(NodeTraversal t, Node n, JSTypeNative type) { ensureTyped(t, n, getNativeType(type)); } /** * Enforces type casts, and ensures the node is typed. * * A cast in the way that we use it in JSDoc annotations never * alters the generated code and therefore never can induce any runtime * operation. What this means is that a 'cast' is really just a compile * time constraint on the underlying value. In the future, we may add * support for run-time casts for compiled tests. * * To ensure some shred of sanity, we enforce the notion that the * type you are casting to may only meaningfully

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> be a narrower type * than the underlying declared type. We also invalidate optimizations * on bad type casts. * * @param t The traversal object needed to report errors. * @param n The node getting a type assigned to it. * @param type The type to be assigned. */ private void ensureTyped(NodeTraversal t, Node n, JSType type) { // Make sure FUNCTION nodes always get function type. Preconditions.checkState(n.getType() != Token.FUNCTION || type instanceof FunctionType || type.isUnknownType()); JSDocInfo info = n.getJSDocInfo(); if (info != null) { if (info.hasType()) { JSType infoType = info.getType().evaluate(t.getScope(), typeRegistry); validator.expectCanCast(t, n, infoType, type); type = infoType; } if (info.isImplicitCast() && !inExterns) { String propName = n.getType() == Token.GETPROP ? n.getLastChild().getString() : "(missing)"; compiler.report( t.makeError(n, ILLEGAL_IMPLICIT_CAST, propName)); } } if (n.getJSType() == null) { n.setJSType(type); } } /** * Returns the percentage of nodes typed by the type checker. * @return a number between 0.0 and 100.0 */ double getTypedPercent() { int total = nullCount + unknownCount + typedCount; if (total == 0) { return 0.0; } else { return (100.0 * typedCount) / total; } } private JSType getNativeType(JSTypeNative typeId) { return typeRegistry.getNativeType(typeId); } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; /** * An unresolved type that was forward declared. So we know it exists, * but that it wasn't pulled into this binary. * * In most cases, it behaves like a bottom type in the type lattice: * no real type should be assigned to a NoResolvedType, but the * NoResolvedType is a subtype of everything. In a few cases, it behaves * like the unknown type: properties of this type are also NoResolved types, * and comparisons to other types always have an unknown result. * * @author nicksantos@google.com (Nick Santos) */ class NoResolvedType extends NoType { private static final long serialVersionUID = 1L; NoResolvedType(JSTypeRegistry registry) { super(registry); } @Override public boolean isNoResolvedType() { return true; } @Override public boolean isNoType() { return false; } @Override public JSType getPropertyType(String propertyName) { return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE); } @Override public boolean isSubtype(JSType that) { if (JSType.isSubtype(this, that)) { return true; } else { return !that.isNoType(); } } @Override public String toString() { return "NoResolvedType"; } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import com.google.javascript.rhino.ErrorReporter; /** * Value types (null, void, number, boolean, string). */ abstract class ValueType extends JSType { ValueType(JSTypeRegistry registry) { super(registry); } @Override public boolean isSubtype(JSType that) { return JSType.isSubtype(this, that); } @Override final JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { return this; } @Override public boolean hasDisplayName() { return true; } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>. private boolean prettyPrint = false; private static final int MAX_PRETTY_PRINTED_PROPERTIES = 4; /** * Creates an object type. * * @param className the name of the class. May be {@code null} to * denote an anonymous class. * * @param implicitPrototype the implicit prototype * (a.k.a. {@code [[Prototype]]}) as defined by ECMA-262. If the * implicit prototype is {@code null} the implicit prototype will be * set to the {@link JSTypeNative#OBJECT_TYPE}. */ PrototypeObjectType(JSTypeRegistry registry, String className, ObjectType implicitPrototype) { this(registry, className, implicitPrototype, false); } /** * Creates an object type, allowing specification of the implicit prototype * when creating native objects. */ PrototypeObjectType(JSTypeRegistry registry, String className, ObjectType implicitPrototype, boolean nativeType) { super(registry); this.properties = Maps.newTreeMap(); this.className = className; this.nativeType = nativeType; if (nativeType || implicitPrototype != null) { setImplicitPrototype(implicitPrototype); } else { setImplicitPrototype( registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE)); } } /** * Gets the number of properties of this object. */ @Override public int getPropertiesCount() { ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype == null) { return this.properties.size(); } int localCount = 0; for (String property : properties.keySet()) { if (!implicitPrototype.hasProperty(property)) { localCount++; } } return implicitPrototype.getPropertiesCount() + localCount; } @Override public boolean hasProperty(String propertyName) { if (properties.get(propertyName) != null) { return true; } ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { return implicitPrototype.hasProperty(propertyName); } return false; } @Override public boolean hasOwnProperty(String propertyName) { return properties.get(propertyName) != null; } @Override public Set<String> getOwnPropertyNames() { return properties.keySet(); } @Override public boolean isPropertyTypeDeclared(String property) { Property p = properties.get(property); if (p == null) { ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { return implicitPrototype.isPropertyTypeDeclared(property); } // property does not exist return false; } return !p.inferred; } @Override void collectPropertyNames(Set<String> props) { for (String prop : properties.keySet()) { props.add(prop); } ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { implicitPrototype.collectPropertyNames(props); } } @Override public boolean isPropertyTypeInferred(String property) { Property p = properties.get(property); if (p == null) { ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { return implicitPrototype.isPropertyTypeInferred(property); } // property does not exist return false; } return p.inferred; } @Override public JSType getPropertyType(String propertyName) { Property p = properties.get(propertyName); if (p != null) { return p.type; } ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype !=

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> null) { return implicitPrototype.getPropertyType(propertyName); } return getNativeType(JSTypeNative.UNKNOWN_TYPE); } @Override public boolean isPropertyInExterns(String propertyName) { Property p = properties.get(propertyName); if (p != null) { return p.inExterns; } ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { return implicitPrototype.isPropertyInExterns(propertyName); } return false; } @Override boolean defineProperty(String name, JSType type, boolean inferred, boolean inExterns, Node propertyNode) { if (hasOwnDeclaredProperty(name)) { return false; } properties.put(name, new Property(type, inferred, inExterns, propertyNode)); return true; } @Override public Node getPropertyNode(String propertyName) { Property p = properties.get(propertyName); if (p != null) { return p.propertyNode; } ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { return implicitPrototype.getPropertyNode(propertyName); } return null; } @Override public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) { Property p = properties.get(propertyName); if (p != null) { return p.docInfo; } return null; } @Override public void setPropertyJSDocInfo(String propertyName, JSDocInfo info, boolean inExterns) { if (info != null) { if (!properties.containsKey(propertyName)) { // If docInfo was attached, but the type of the property // was not defined anywhere, then we consider this an explicit // declaration of the property. defineInferredProperty(propertyName, getPropertyType(propertyName), inExterns, null); } // The prototype property is not represented as a normal Property. // We probably don't want to attach any JSDoc to it anyway. Property property = properties.get(propertyName); if (property != null) { property.docInfo = info; } } } @Override public boolean matchesNumberContext() { return isNumberObjectType() || isDateType() || isBooleanObjectType() || isStringObjectType() || hasOverridenNativeProperty("valueOf"); } @Override public boolean matchesStringContext() { return isTheObjectType() || isStringObjectType() || isDateType() || isRegexpType() || isArrayType() || isNumberObjectType() || isBooleanObjectType() || hasOverridenNativeProperty("toString"); } /** * Given the name of a native object property, checks whether the property is * present on the object and different from the native one. */ private boolean hasOverridenNativeProperty(String propertyName) { if (isNative()) { return false; } JSType propertyType = getPropertyType(propertyName); ObjectType nativeType = this.isFunctionType() ? registry.getNativeObjectType(JSTypeNative.FUNCTION_PROTOTYPE) : registry.getNativeObjectType(JSTypeNative.OBJECT_PROTOTYPE); JSType nativePropertyType = nativeType.getPropertyType(propertyName); return propertyType != nativePropertyType; } @Override public JSType unboxesTo() { if (isStringObjectType()) { return getNativeType(JSTypeNative.STRING_TYPE); } else if (isBooleanObjectType()) { return getNativeType(JSTypeNative.BOOLEAN_TYPE); } else if (isNumberObjectType()) { return getNativeType(JSTypeNative.NUMBER_TYPE

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import static com.google.javascript.rhino.jstype.TernaryValue.FALSE; import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import com.google.javascript.rhino.JSDocInfo; import com.google.javascript.rhino.Node; import java.util.Set; /** * Object type. * * In JavaScript, all object types have properties, and each of those * properties has a type. Property types may be DECLARED, INFERRED, or * UNKNOWN. * * DECLARED properties have an explicit type annotation, as in: * <code> * /xx @type {number} x/ * Foo.prototype.bar = 1; * </code> * This property may only hold number values, and an assignment to any * other type of value is an error. * * INFERRED properties do not have an explicit type annotation. Rather, * we try to find all the possible types that this property can hold. * <code> * Foo.prototype.bar = 1; * </code> * If the programmer assigns other types of values to this property, * the property will take on the union of all these types. * * UNKNOWN properties are properties on the UNKNOWN type. The UNKNOWN * type has all properties, but we do not know whether they are * declared or inferred. * */ public abstract class ObjectType extends JSType { private boolean visited; private JSDocInfo docInfo = null; private boolean unknown = true; ObjectType(JSTypeRegistry registry) { super(registry); }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> are comparable to everything but null/undefined if (that.isSubtype( getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN))) { return UNKNOWN; } else { return FALSE; } } /** * Gets this object's constructor. * @return this object's constructor or {@code null} if it is a native * object (constructed natively v.s. by instantiation of a function) */ public abstract FunctionType getConstructor(); /** * Gets the implicit prototype (a.k.a. the {@code [[Prototype]]} property). */ public abstract ObjectType getImplicitPrototype(); /** * Defines a property whose type is synthesized (i.e. not inferred). * @param propertyName the property's name * @param type the type * @param inExterns {@code true} if this property was defined in an externs * file. TightenTypes assumes that any function passed to an externs * property could be called, so setting this incorrectly could result * in live code being removed. * @param propertyNode the node corresponding to the declaration of property * which might later be accessed using {@code getPropertyNode}. */ public final boolean defineDeclaredProperty(String propertyName, JSType type, boolean inExterns, Node propertyNode) { boolean result = defineProperty(propertyName, type, false, inExterns, propertyNode); // All property definitions go through this method // or defineDeclaredProperty. Because the properties defined an an // object can affect subtyping, it's slightly more efficient // to register this after defining the property. registry.registerPropertyOnType(propertyName, this); return result; } /** * Defines a property whose type is inferred. * @param propertyName the property's name * @param type the type * @param inExterns {@code true} if this property was defined in an externs * file. TightenTypes assumes that any function passed to an externs * property could be called, so setting this incorrectly could result * in live code being removed. * @param propertyNode the node corresponding to the inferred definition of * property that might later be accessed using {@code getPropertyNode}. */ public final boolean defineInferredProperty(String propertyName, JSType type, boolean inExterns, Node propertyNode) { if (hasProperty(propertyName)) { JSType originalType = getPropertyType(propertyName); type = originalType == null ? type : originalType.getLeastSupertype(type); } boolean result = defineProperty(propertyName, type, true, inExterns, propertyNode); // All property definitions go through this method // or defineDeclaredProperty. Because the properties defined an an // object can affect subtyping, it's slightly more efficient // to register this after defining the property. registry.registerPropertyOnType(propertyName, this); return result; } /** * Defines a property.<p> * * For clarity, callers should prefer {@link #defineDeclaredProperty} and * {@link #defineInferredProperty}. * * @param propertyName the property's name * @param type the type * @param inferred {@code true} if this property's type is inferred * @param inExterns {@code true} if this property was defined in an externs * file. TightenTypes assumes that any function passed to an externs * property could be called, so setting this incorrectly could result * in live code being removed. * @param propertyNode the node that represents the definition of property. * Depending

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> existing typing logic is hacky. Unresolved types should get processed * in a more consistent way, but with the Rhino merge coming, there will be * much that has to be changed.<p> * */ class NamedType extends ProxyObjectType { private static final long serialVersionUID = 1L; private final String reference; private final String sourceName; private final int lineno; private final int charno; /** * Validates the type resolution. */ private Predicate<JSType> validator; /** * If true, don't warn about unresolveable type names. * * NOTE(nicksantos): A lot of third-party code doesn't use our type syntax. * They have code like * {@code @return} the bus. * and they clearly don't mean that "the" is a type. In these cases, we're * forgiving and try to guess whether or not "the" is a type when it's not * clear. */ private boolean forgiving = false; /** * Create a named type based on the reference. */ NamedType(JSTypeRegistry registry, String reference, String sourceName, int lineno, int charno) { super(registry, registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE)); Preconditions.checkNotNull(reference); this.reference = reference; this.sourceName = sourceName; this.lineno = lineno; this.charno = charno; } @Override void forgiveUnknownNames() { forgiving = true; } /** Returns the type to which this refers (which is unknown if unresolved). */ public JSType getReferencedType() { return getReferencedTypeInternal(); } @Override public String getReferenceName() { return reference; } @Override public String toString() { return reference; } @Override public boolean hasReferenceName() { return true; } @Override boolean isNamedType() { return true; } @Override public boolean isNominalType() { return true; } /** * Two named types are equivalent if they are the same {@code * ObjectType} object. This is complicated by the fact that isEquivalent * is sometimes called before we have a chance to resolve the type * names. * * @return {@code true} iff {@code that} == {@code this} or {@code that} * is a {@link NamedType} whose reference is the same as ours, * or {@code that} is the type we reference. */ @Override public boolean isEquivalentTo(JSType that) { if (this == that) { return true; } ObjectType objType = ObjectType.cast(that); if (objType != null) { return objType.isNominalType() && reference.equals(objType.getReferenceName()); } return false; } @Override public int hashCode() { return reference.hashCode(); } /** * Resolve the referenced type within the enclosing scope. */ @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> enclosing) { // TODO(user): Investigate whether it is really necessary to keep two // different mechanisms for resolving named types, and if so, which order // makes more sense. Now, resolution via registry is first in order to // avoid triggering the warnings built into the resolution via properties. boolean resolved = resolveViaRegistry(t, enclosing); if (detectImplicitPrototypeCycle()) { handleTypeCycle(t); } if (resolved) { super.

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>resolveInternal(t, enclosing); return registry.isLastGeneration() ? getReferencedType() : this; } resolveViaProperties(t, enclosing); if (detectImplicitPrototypeCycle()) { handleTypeCycle(t); } super.resolveInternal(t, enclosing); return registry.isLastGeneration() ? getReferencedType() : this; } /** * Resolves a named type by looking it up in the registry. * @return True if we resolved successfully. */ private boolean resolveViaRegistry( ErrorReporter t, StaticScope<JSType> enclosing) { JSType type = registry.getType(reference); if (type != null) { setReferencedAndResolvedType(type, t, enclosing); return true; } return false; } /** * Resolves a named type by looking up its first component in the scope, and * subsequent components as properties. The scope must have been fully * parsed and a symbol table constructed. */ private void resolveViaProperties(ErrorReporter t, StaticScope<JSType> enclosing) { JSType value = lookupViaProperties(t, enclosing); // last component of the chain if ((value instanceof FunctionType) && (value.isConstructor() || value.isInterface())) { FunctionType functionType = (FunctionType) value; setReferencedAndResolvedType( functionType.getInstanceType(), t, enclosing); } else if (value instanceof EnumType) { setReferencedAndResolvedType( ((EnumType) value).getElementsType(), t, enclosing); } else { // We've been running into issues where people forward-declare // non-named types. (This is legitimate...our dependency management // code doubles as our forward-declaration code.) // // So if the type does resolve to an actual value, but it's not named, // then don't respect the forward declaration. handleUnresolvedType(t, value == null || value.isUnknownType()); } } /** * Resolves a type by looking up its first component in the scope, and * subsequent components as properties. The scope must have been fully * parsed and a symbol table constructed. * @return The type of the symbol, or null if the type could not be found. */ private JSType lookupViaProperties( ErrorReporter t, StaticScope<JSType> enclosing) { String[] componentNames = reference.split("\\.", -1); if (componentNames[0].length() == 0) { return null; } StaticSlot<JSType> slot = enclosing.getSlot(componentNames[0]); if (slot == null) { return null; } // If the first component has a type of 'Unknown', then any type // names using it should be regarded as silently 'Unknown' rather than be // noisy about it. JSType slotType = slot.getType(); if (slotType == null || slotType.isAllType() || slotType.isNoType()) { return null; } JSType value = getTypedefType(t, slot, componentNames[0]); if (value == null) { return null; } // resolving component by component for (int i = 1; i < componentNames.length; i++) { ObjectType parentClass = ObjectType.cast(value); if (parentClass == null) { return null; } if (componentNames[i].length() == 0) { return null; } value = parentClass.getPropertyType(componentNames[i]); } return value; }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> private void setReferencedAndResolvedType(JSType type, ErrorReporter t, StaticScope<JSType> enclosing) { if (validator != null) { validator.apply(type); } setReferencedType(type); checkEnumElementCycle(t); setResolvedTypeInternal(getReferencedType()); } private void handleTypeCycle(ErrorReporter t) { setReferencedType( registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE)); t.warning("Cycle detected in inheritance chain of type " + reference, sourceName, lineno, null, charno); setResolvedTypeInternal(getReferencedType()); } private void checkEnumElementCycle(ErrorReporter t) { JSType referencedType = getReferencedType(); if (referencedType instanceof EnumElementType && ((EnumElementType) referencedType).getPrimitiveType() == this) { handleTypeCycle(t); } } // Warns about this type being unresolved iff it's not a forward-declared // type name. private void handleUnresolvedType( ErrorReporter t, boolean ignoreForwardReferencedTypes) { if (registry.isLastGeneration()) { boolean isForwardDeclared = ignoreForwardReferencedTypes && registry.isForwardDeclaredType(reference); boolean beForgiving = forgiving || isForwardDeclared; if (!beForgiving && registry.isLastGeneration()) { t.warning("Unknown type " + reference, sourceName, lineno, null, charno); } else { if (isForwardDeclared) { setReferencedType( registry.getNativeObjectType( JSTypeNative.NO_RESOLVED_TYPE)); } else { setReferencedType( registry.getNativeObjectType( JSTypeNative.CHECKED_UNKNOWN_TYPE)); } if (registry.isLastGeneration() && validator != null) { validator.apply(getReferencedType()); } } setResolvedTypeInternal(getReferencedType()); } else { setResolvedTypeInternal(this); } } JSType getTypedefType(ErrorReporter t, StaticSlot<JSType> slot, String name) { JSType type = slot.getType(); if (type != null) { return type; } handleUnresolvedType(t, true); return null; } @Override public boolean setValidator(Predicate<JSType> validator) { // If the type is already resolved, we can validate it now. If // the type has not been resolved yet, we need to wait till its // resolved before we can validate it. if (this.isResolved()) { return super.setValidator(validator); } else { this.validator = validator; return true; } } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; /** * Bottom type, representing the subclass of any value or object. * * Although JavaScript programmers can't explicitly denote the bottom type, * it comes up in static analysis. For example, if we have: * <code> * var x = null; * if (x) { * f(x); * } * </code> * We need to be able to assign {@code x} a type within the {@code f(x)} * call. Since it has no possible type, we assign {@code x} the NoType, * so that {@code f(x)} is legal no matter what the type of {@code f}'s * first argument is. * * @see <a href="http://en.wikipedia.org/wiki/Bottom_type">Bottom types</a> */ public class NoType extends NoObjectType { private static final long serialVersionUID = 1L; NoType(JSTypeRegistry registry) { super(registry); } @Override public boolean isNoObjectType() { return false; } @Override public boolean isNoType() { return true; } @Override public boolean isNullable() { return true; } @Override public boolean isSubtype(JSType that) { return true; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.EMPTY; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesObjectContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseNoType

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import static com.google.javascript.rhino.jstype.TernaryValue.FALSE; import static com.google.javascript.rhino.jstype.TernaryValue.TRUE; import com.google.javascript.rhino.ErrorReporter; import com.google.javascript.rhino.Node; import java.util.Collections; import java.util.HashSet; import java.util.Set; /** * An enum type representing a branded collection of elements. Each element * is referenced by its name, and has an {@link EnumElementType} type. */ public class EnumType extends PrototypeObjectType { private static final long serialVersionUID = 1L; // the type of the individual elements private EnumElementType elementsType; // the elements' names (they all have the same type) private final Set<String> elements = new HashSet<String>(); /** * Creates an enum type. * * @param name the enum's name * @param elementsType the base type of the individual elements */ EnumType(JSTypeRegistry registry, String name, JSType elementsType) { super(registry, "enum{" + name + "}", null); this.elementsType = new EnumElementType(registry, elementsType, name); } @Override public boolean isEnumType() { return true; } @Override public ObjectType getImplicitPrototype() { return registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE); } /** * Gets the elements defined on this enum. * @return the elements' names defined on this enum. The returned set is * immutable. */ public Set<String> getElements() { return Collections.unmodifiableSet(elements); } /** * Defines a new element on this enum.

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> * @param name the name of the new element * @param definingNode the {@code Node} that defines this new element * @return true iff the new element is added successfully */ public boolean defineElement(String name, Node definingNode) { elements.add(name); return defineDeclaredProperty(name, elementsType, false, definingNode); } /** * Gets the elements' type. */ public EnumElementType getElementsType() { return elementsType; } @Override public TernaryValue testForEquality(JSType that) { TernaryValue result = super.testForEquality(that); if (result != null) { return result; } return this.isEquivalentTo(that) ? TRUE : FALSE; } @Override public boolean isSubtype(JSType that) { return that.isEquivalentTo(getNativeType(JSTypeNative.OBJECT_TYPE)) || that.isEquivalentTo(getNativeType(JSTypeNative.OBJECT_PROTOTYPE)) || JSType.isSubtype(this, that); } @Override public String toString() { return getReferenceName(); } @Override public String getDisplayName() { return elementsType.getDisplayName(); } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseObjectType(this); } @Override public FunctionType getConstructor() { return null; } @Override public boolean matchesNumberContext() { return false; } @Override public boolean matchesStringContext() { return true; } @Override public boolean matchesObjectContext() { return true; } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { elementsType = (EnumElementType) elementsType.resolve(t, scope); return super.resolveInternal(t, scope); } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; /** * An object type with a declared default element type, such as * <code>Array.<string></code>. * * // TODO(user): Define the subtyping relation for parameterized types. Also, * take parameterized type into account for equality. * */ final class ParameterizedType extends ProxyObjectType { private static final long serialVersionUID = 1L; final JSType parameterType; ParameterizedType( JSTypeRegistry registry, ObjectType objectType, JSType parameterType) { super(registry, objectType); this.parameterType = parameterType; } @Override public JSType getParameterType() { return parameterType; } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import com.google.common.collect.ImmutableSet; import com.google.javascript.rhino.ErrorReporter; import com.google.javascript.rhino.JSDocInfo; import com.google.javascript.rhino.Node; import java.util.Collections; import java.util.Set; /** * An object type which uses composition to delegate all calls. * * @see NamedType * @see ParameterizedType * */ class ProxyObjectType extends ObjectType { private static final long serialVersionUID = 1L; private JSType referencedType; private ObjectType referencedObjType; ProxyObjectType(JSTypeRegistry registry, JSType referencedType) { super(registry); setReferencedType(referencedType); } JSType getReferencedTypeInternal() { return referencedType; } void setReferencedType(JSType referencedType) { this.referencedType = referencedType; if (referencedType instanceof ObjectType) { this.referencedObjType = (ObjectType) referencedType; } else { this.referencedObjType = null; } } @Override public String getReferenceName() { return referencedObjType == null ? "" : referencedObjType.getReferenceName(); } @Override public boolean hasReferenceName() { return referencedObjType == null ? null : referencedObjType.hasReferenceName(); } @Override public boolean matchesNumberContext() { return referencedType.matchesNumberContext(); } @Override public boolean matchesStringContext() { return referencedType.matchesStringContext(); } @Override public boolean matchesObjectContext() { return referencedType.matchesObjectContext(); } @Override public boolean canBeCalled() { return referencedType.canBeCalled(); } @Override public boolean isNoType()

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>Type findPropertyType(String propertyName) { return referencedType.findPropertyType(propertyName); } @Override public JSType getPropertyType(String propertyName) { return referencedObjType == null ? getNativeType(JSTypeNative.UNKNOWN_TYPE) : referencedObjType.getPropertyType(propertyName); } @Override public JSDocInfo getJSDocInfo() { return referencedType.getJSDocInfo(); } @Override public void setJSDocInfo(JSDocInfo info) { if (referencedObjType != null) { referencedObjType.setJSDocInfo(info); } } @Override public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) { return referencedObjType == null ? null : referencedObjType.getOwnPropertyJSDocInfo(propertyName); } @Override public void setPropertyJSDocInfo(String propertyName, JSDocInfo info, boolean inExterns) { if (referencedObjType != null) { referencedObjType.setPropertyJSDocInfo(propertyName, info, inExterns); } } @Override public boolean hasProperty(String propertyName) { return referencedObjType == null ? false : referencedObjType.hasProperty(propertyName); } @Override public boolean hasOwnProperty(String propertyName) { return referencedObjType == null ? false : referencedObjType.hasOwnProperty(propertyName); } @Override public Set<String> getOwnPropertyNames() { return referencedObjType == null ? ImmutableSet.<String>of() : referencedObjType.getOwnPropertyNames(); } @Override public FunctionType getConstructor() { return referencedObjType == null ? null : referencedObjType.getConstructor(); } @Override public JSType getParameterType() { return referencedObjType == null ? null : referencedObjType.getParameterType(); } @Override public JSType getIndexType() { return referencedObjType == null ? null : referencedObjType.getIndexType(); } @Override public <T> T visit(Visitor<T> visitor) { return referencedType.visit(visitor); } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { setReferencedType(referencedType.resolve(t, scope)); return this; } @Override public String toDebugHashCodeString() { return "{proxy:" + referencedType.toDebugHashCodeString() + "}"; } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; /** * A builder for the Rhino Node representing Function parameters. * @author nicksantos@google.com (Nick Santos) */ public class FunctionParamBuilder { private final JSTypeRegistry registry; private final Node root = new Node(Token.LP); public FunctionParamBuilder(JSTypeRegistry registry) { this.registry = registry; } /** * Add parameters of the given type to the end of the param list. * @return False if this is called after optional params are added. */ public boolean addRequiredParams(JSType ...types) { if (hasOptionalOrVarArgs()) { return false; } for (JSType type : types) { newParameter(type); } return true; } /** * Add optional parameters of the given type to the end of the param list. * @param types Types for each optional parameter. The builder will make them * undefineable. * @return False if this is called after var args are added. */ public boolean addOptionalParams(JSType ...types) { if (hasVarArgs()) { return false; } for (JSType type : types) { newParameter(registry.createOptionalType(type)).setOptionalArg(true); } return true; } /** * Add variable arguments to the end of the parameter list. * @return False if this is called after var args are added. */ public boolean addVarArgs(JSType type) { if (hasVarArgs()) { return false; } // There are two types of variable argument functions: // 1) Programmer

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>-defined var args // 2) Native bottom types that can accept any argument. // For the first one, "undefined" is a valid value for all arguments. // For the second, we do not want to cast it up to undefined. if (!type.isEmptyType()) { type = registry.createOptionalType(type); } newParameter(type).setVarArgs(true); return true; } /** * Copies the parameter specification from the given node. */ public Node newParameterFromNode(Node n) { Node newParam = newParameter(n.getJSType()); newParam.setVarArgs(n.isVarArgs()); newParam.setOptionalArg(n.isOptionalArg()); return newParam; } // Add a parameter to the list with the given type. private Node newParameter(JSType type) { Node paramNode = Node.newString(Token.NAME, ""); paramNode.setJSType(type); root.addChildToBack(paramNode); return paramNode; } public Node build() { return root; } private boolean hasOptionalOrVarArgs() { Node lastChild = root.getLastChild(); return lastChild != null && (lastChild.isOptionalArg() || lastChild.isVarArgs()); } public boolean hasVarArgs() { Node lastChild = root.getLastChild(); return lastChild != null && lastChild.isVarArgs(); } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>, ObjectType delegator, FunctionType delegateProxy, FunctionType findDelegate); /** * @return the name of the delegate superclass. */ public String getDelegateSuperclassName(); /** * Defines the delegate proxy prototype properties. Their types depend on * properties of the delegate base methods. * * @param delegateProxyPrototypes List of delegate proxy prototypes. */ public void defineDelegateProxyPrototypeProperties( JSTypeRegistry registry, Scope scope, List<ObjectType> delegateProxyPrototypes); /** * Gets the name of the global object. */ public String getGlobalObject(); /** * Whether this CALL function is testing for the existence of a property. */ public boolean isPropertyTestFunction(Node call); /** * Checks if the given method performs a object literal cast, and if it does, * returns information on the cast. By default, always returns null. Meant * to be overridden by subclasses. * * @param t The node traversal. * @param callNode A CALL node. */ public ObjectLiteralCast getObjectLiteralCast(NodeTraversal t, Node callNode); /** * Returns the set of AssertionFunction. */ public Collection<AssertionFunctionSpec> getAssertionFunctions(); static enum SubclassType { INHERITS, MIXIN } static class SubclassRelationship { final SubclassType type; final String subclassName; final String superclassName; SubclassRelationship(SubclassType type, Node subclassNode, Node superclassNode) { this.type = type; this.subclassName = subclassNode.getQualifiedName(); this.superclassName = superclassNode.getQualifiedName(); } } /** * Delegates provides a mechanism and structure for identifying where classes * can call out to optional code to augment their functionality. The optional * code is isolated from the base code through the use of a subclass in the * optional code derived from the delegate class in the base code. */ static class DelegateRelationship { /** The subclass in the base code. */ final String delegateBase; /** The class in the base code. */ final String delegator; DelegateRelationship(String delegateBase, String delegator) { this.delegateBase = delegateBase; this.delegator = delegator; } } /** * An object literal cast provides a mechanism to cast object literals to * other types without a warning. */ static class ObjectLiteralCast { /** Type to cast to. */ final String typeName; /** Object to cast. */ final Node objectNode; ObjectLiteralCast(String typeName, Node objectNode) { this.typeName = typeName; this.objectNode = objectNode; } } /** * A function that will throw an exception when either: * -One or more of its parameters evaluate to false. * -One or more of its parameters are not of a certain type. */ public class AssertionFunctionSpec { private final String functionName; private final JSTypeNative assertedType; public AssertionFunctionSpec(String functionName) { this(functionName, null); } public AssertionFunctionSpec(String functionName, JSTypeNative assertedType) { this.functionName = functionName; this.assertedType = assertedType; } /** Returns the name of the function. */ public String getFunctionName() { return functionName; } /** * Returns the parameter of the assertion function that is being checked. * @param firstParam The first parameter of the function call. */ public Node getAssertedParam(Node firstParam) { return firstParam; } /** * Returns

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> the type for a type assertion, or null if the function asserts * that the node must not be null or undefined. */ public JSTypeNative getAssertedType() { return assertedType; } } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.javascript.rhino.ErrorReporter; import java.util.Collection; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; /** * The {@code UnionType} implements a common JavaScript idiom in which the * code is specifically designed to work with multiple input types. Because * JavaScript always knows the runtime type of an object value, this is safer * than a C union.<p> * * For instance, values of the union type {@code (String,boolean)} can be of * type {@code String} or of type {@code boolean}. The commutativity of the * statement is captured by making {@code (String,boolean)} and * {@code (boolean,String)} equal.<p> * * The implementation of this class prevents the creation of nested * unions.<p> */ public class UnionType extends JSType { private static final long serialVersionUID = 1L; Collection<JSType> alternates; private final int hashcode; /** * Creates a union type. * * @param alternates the alternates of the union */ UnionType(JSTypeRegistry registry, Collection<JSType> alternates) { super(registry); this.alternates = alternates; this.hashcode = this.alternates.hashCode(); } /** * Gets

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> } @Override public boolean canBeCalled() { for (JSType t : alternates) { if (!t.canBeCalled()) { return false; } } return true; } @Override public JSType restrictByNotNullOrUndefined() { UnionTypeBuilder restricted = new UnionTypeBuilder(registry); for (JSType t : alternates) { restricted.addAlternate(t.restrictByNotNullOrUndefined()); } return restricted.build(); } @Override public TernaryValue testForEquality(JSType that) { TernaryValue result = null; for (JSType t : alternates) { TernaryValue test = t.testForEquality(that); if (result == null) { result = test; } else if (!result.equals(test)) { return UNKNOWN; } } return result; } /** * This predicate determines whether objects of this type can have the * {@code null} value, and therefore can appear in contexts where * {@code null} is expected. * * @return {@code true} for everything but {@code Number} and * {@code Boolean} types. */ @Override public boolean isNullable() { for (JSType t : alternates) { if (t.isNullable()) { return true; } } return false; } @Override public boolean isUnknownType() { for (JSType t : alternates) { if (t.isUnknownType()) { return true; } } return false; } @Override public JSType getLeastSupertype(JSType that) { if (!that.isUnknownType() && !that.isUnionType()) { for (JSType alternate : alternates) { if (!alternate.isUnknownType() && that.isSubtype(alternate)) { return this; } } } return getLeastSupertype(this, that); } JSType meet(JSType that) { UnionTypeBuilder builder = new UnionTypeBuilder(registry); for (JSType alternate : alternates) { if (alternate.isSubtype(that)) { builder.addAlternate(alternate); } } if (that instanceof UnionType) { for (JSType otherAlternate : ((UnionType) that).alternates) { if (otherAlternate.isSubtype(this)) { builder.addAlternate(otherAlternate); } } } else if (that.isSubtype(this)) { builder.addAlternate(that); } JSType result = builder.build(); if (!result.isNoType()) { return result; } else if (this.isObject() && that.isObject()) { return getNativeType(JSTypeNative.NO_OBJECT_TYPE); } else { return getNativeType(JSTypeNative.NO_TYPE); } } /** * Two union types are equal if they have the same number of alternates * and all alternates are equal. */ @Override public boolean isEquivalentTo(JSType object) { if (object instanceof UnionType) { UnionType that = (UnionType) object; if (alternates.size() != that.alternates.size()) { return false; } for (JSType alternate : that.alternates) { if (!hasAlternate(alternate)) { return false; } } return true; } else { return false; } } private boolean hasAlternate(JSType type) { for (JSType alternate : alternates) { if (alternate.isEquivalent

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>To(type)) { return true; } } return false; } @Override public int hashCode() { return this.hashcode; } @Override public boolean isUnionType() { return true; } @Override public boolean isObject() { for (JSType alternate : alternates) { if (!alternate.isObject()) { return false; } } return true; } /** * A {@link UnionType} contains a given type (alternate) iff the member * vector contains it. * * @param alternate The alternate which might be in this union. * * @return {@code true} if the alternate is in the union */ public boolean contains(JSType type) { for (JSType alt : alternates) { if (alt.isEquivalentTo(type)) { return true; } } return false; } /** * Returns a more restricted union type than {@code this} one, in which all * subtypes of {@code type} have been removed.<p> * * Examples: * <ul> * <li>{@code (number,string)} restricted by {@code number} is * {@code string}</li> * <li>{@code (null, EvalError, URIError)} restricted by * {@code Error} is {@code null}</li> * </ul> * * @param type the supertype of the types to remove from this union type */ public JSType getRestrictedUnion(JSType type) { UnionTypeBuilder restricted = new UnionTypeBuilder(registry); for (JSType t : alternates) { if (t.isUnknownType() || !t.isSubtype(type)) { restricted.addAlternate(t); } } return restricted.build(); } @Override public String toString() { StringBuilder result = new StringBuilder(); boolean firstAlternate = true; result.append("("); SortedSet<JSType> sorted = new TreeSet<JSType>(ALPHA); sorted.addAll(alternates); for (JSType t : sorted) { if (!firstAlternate) { result.append("|"); } result.append(t.toString()); firstAlternate = false; } result.append(")"); return result.toString(); } @Override public boolean isSubtype(JSType that) { // unknown if (that.isUnknownType()) { return true; } // all type if (that.isAllType()) { return true; } for (JSType element : alternates) { if (!element.isSubtype(that)) { return false; } } return true; } @Override public JSType getRestrictedTypeGivenToBooleanOutcome(boolean outcome) { // gather elements after restriction UnionTypeBuilder restricted = new UnionTypeBuilder(registry); for (JSType element : alternates) { restricted.addAlternate( element.getRestrictedTypeGivenToBooleanOutcome(outcome)); } return restricted.build(); } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { BooleanLiteralSet literals = BooleanLiteralSet.EMPTY; for (JSType element : alternates) { literals = literals.union(element.getPossibleToBooleanOutcomes()); if (literals == BooleanLiteralSet.BOTH) { break; } } return literals; } @Override public TypePair getTypesUnderEquality(JSType that) { UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry); UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry);

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> for (JSType element : alternates) { TypePair p = element.getTypesUnderEquality(that); if (p.typeA != null) { thisRestricted.addAlternate(p.typeA); } if (p.typeB != null) { thatRestricted.addAlternate(p.typeB); } } return new TypePair( thisRestricted.build(), thatRestricted.build()); } @Override public TypePair getTypesUnderInequality(JSType that) { UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry); UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry); for (JSType element : alternates) { TypePair p = element.getTypesUnderInequality(that); if (p.typeA != null) { thisRestricted.addAlternate(p.typeA); } if (p.typeB != null) { thatRestricted.addAlternate(p.typeB); } } return new TypePair( thisRestricted.build(), thatRestricted.build()); } @Override public TypePair getTypesUnderShallowInequality(JSType that) { UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry); UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry); for (JSType element : alternates) { TypePair p = element.getTypesUnderShallowInequality(that); if (p.typeA != null) { thisRestricted.addAlternate(p.typeA); } if (p.typeB != null) { thatRestricted.addAlternate(p.typeB); } } return new TypePair( thisRestricted.build(), thatRestricted.build()); } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseUnionType(this); } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { setResolvedTypeInternal(this); // for circularly defined types. boolean changed = false; ImmutableList.Builder<JSType> resolvedTypes = ImmutableList.builder(); for (JSType alternate : alternates) { JSType newAlternate = alternate.resolve(t, scope); changed |= (alternate != newAlternate); resolvedTypes.add(alternate); } if (changed) { Collection<JSType> newAlternates = resolvedTypes.build(); Preconditions.checkState( newAlternates.hashCode() == this.hashcode); alternates = newAlternates; } return this; } @Override public String toDebugHashCodeString() { List<String> hashCodes = Lists.newArrayList(); for (JSType a : alternates) { hashCodes.add(a.toDebugHashCodeString()); } return "{(" + Joiner.on(",").join(hashCodes) + ")}"; } @Override public boolean setValidator(Predicate<JSType> validator) { for (JSType a : alternates) { a.setValidator(validator); } return true; } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import com.google.javascript.rhino.ErrorReporter; import com.google.javascript.rhino.JSDocInfo; import com.google.javascript.rhino.Node; /** * The bottom Object type, representing the subclass of all objects. * * Although JavaScript programmers can't explicitly denote the bottom * Object type, it comes up in static analysis. For example, if we have: * <code> * var x = function() {}; * if (x instanceof Array) { * f(x); * } * </code> * We need to be able to assign {@code x} a type within the {@code f(x)} * call. It has no possible type, but {@code x} would not be legal if f * expected a string. So we assign it the {@code NoObjectType}. * * @see <a href="http://en.wikipedia.org/wiki/Bottom_type">Bottom types</a> */ public class NoObjectType extends FunctionType { private static final long serialVersionUID = 1L; NoObjectType(JSTypeRegistry registry) { super(registry, null, null, registry.createArrowType(null, null), null, null, true, true); getInternalArrowType().returnType = this; this.setInstanceType(this); } @Override public boolean isSubtype(JSType that) { if (JSType.isSubtype(this, that)) { return true; } else { return that.isObject() && !that.isNoType() && !that.isNoResolvedType(); } } @Override public boolean isFunctionType() { return false; } @Override public boolean isNoObjectType() { return true;

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> } @Override public ObjectType getImplicitPrototype() { return null; } @Override public String getReferenceName() { return null; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesObjectContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public boolean isEquivalentTo(JSType that) { return this == that; } @Override public int hashCode() { return System.identityHashCode(this); } @Override public int getPropertiesCount() { // Should never be called, returning the biggest number to highlight the // 'unifying' role of this type. return Integer.MAX_VALUE; } @Override public JSType getPropertyType(String propertyName) { // Return the least type to be a proper subtype of all other objects. return getNativeType(JSTypeNative.NO_TYPE); } @Override public boolean hasProperty(String propertyName) { // has all properties, since it is any object return true; } @Override boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns, Node propertyNode) { // nothing, all properties are defined return true; } @Override public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) { return null; } @Override public void setPropertyJSDocInfo(String propertyName, JSDocInfo info, boolean inExterns) { // Do nothing, specific properties do not have JSDocInfo. } @Override public boolean isPropertyTypeInferred(String propertyName) { return false; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseNoObjectType(); } @Override public String toString() { return "NoObject"; } @Override public FunctionType getConstructor() { return null; } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { return this; } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> public void applySingletonGetter(FunctionType functionType, FunctionType getterType, ObjectType objectType) { // do nothing. } @Override public DelegateRelationship getDelegateRelationship(Node callNode) { return null; } @Override public void applyDelegateRelationship( ObjectType delegateSuperclass, ObjectType delegateBase, ObjectType delegator, FunctionType delegateProxy, FunctionType findDelegate) { // do nothing. } @Override public String getDelegateSuperclassName() { return null; } @Override public void defineDelegateProxyPrototypeProperties( JSTypeRegistry registry, Scope scope, List<ObjectType> delegateProxyPrototypes) { // do nothing. } @Override public String getGlobalObject() { return "window"; } @Override public boolean isPropertyTestFunction(Node call) { return false; } @Override public ObjectLiteralCast getObjectLiteralCast(NodeTraversal t, Node callNode) { return null; } @Override public Collection<AssertionFunctionSpec> getAssertionFunctions() { return Collections.emptySet(); } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; /** * Constants corresponding to types that are built into a JavaScript engine * and other types that occur very often in the type system. See * {@link com.google.javascript.rhino.jstype.JSTypeRegistry#getNativeType(JSTypeNative)}. */ public enum JSTypeNative { // Built-in types (please keep alphabetized) ARRAY_TYPE, ARRAY_FUNCTION_TYPE, BOOLEAN_TYPE, BOOLEAN_OBJECT_TYPE, BOOLEAN_OBJECT_FUNCTION_TYPE, /** * A checked unknown type is a type that we know something about, * but we're not really sure what we know about it. * * Examples of checked unknown types include: * <code> * if (x) { // x is unknown * alert(x); // x is checked unknown * } * </code> * * <code> * /* @param {SomeForwardDeclaredType} x / * function f(x) { * // x is checked unknown. We know it's some type, but the type * // has not been included in this binary. * } * </code> * * This is useful for missing property warnings, where we don't * want to emit warnings on things that have been checked. */ CHECKED_UNKNOWN_TYPE, DATE_TYPE, DATE_FUNCTION_TYPE, ERROR_FUNCTION_TYPE, ERROR_TYPE, EVAL_ERROR_FUNCTION_TYPE, EVAL_ERROR_TYPE, FUNCTION_FUNCTION_TYPE, FUNCTION_INSTANCE_TYPE, // equivalent to U2U_CONSTRUCTOR_TYPE FUNCTION_PROTOTYPE, NULL_TYPE, NUMBER_TYPE, NUMBER_OBJECT_TYPE, NUMBER_OBJECT_FUNCTION_TYPE,

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> OBJECT_TYPE, OBJECT_FUNCTION_TYPE, OBJECT_PROTOTYPE, RANGE_ERROR_FUNCTION_TYPE, RANGE_ERROR_TYPE, REFERENCE_ERROR_FUNCTION_TYPE, REFERENCE_ERROR_TYPE, REGEXP_TYPE, REGEXP_FUNCTION_TYPE, STRING_OBJECT_TYPE, STRING_OBJECT_FUNCTION_TYPE, STRING_TYPE, SYNTAX_ERROR_FUNCTION_TYPE, SYNTAX_ERROR_TYPE, TYPE_ERROR_FUNCTION_TYPE, TYPE_ERROR_TYPE, UNKNOWN_TYPE, URI_ERROR_FUNCTION_TYPE, URI_ERROR_TYPE, VOID_TYPE, // Commonly used types TOP_LEVEL_PROTOTYPE, STRING_VALUE_OR_OBJECT_TYPE, NUMBER_VALUE_OR_OBJECT_TYPE, ALL_TYPE, NO_TYPE, NO_OBJECT_TYPE, NO_RESOLVED_TYPE, GLOBAL_THIS, U2U_CONSTRUCTOR_TYPE, U2U_FUNCTION_TYPE, LEAST_FUNCTION_TYPE, GREATEST_FUNCTION_TYPE, /** * (Object,number,string) */ OBJECT_NUMBER_STRING, /** * (Object,number,string,boolean) */ OBJECT_NUMBER_STRING_BOOLEAN, /** * (number,string,boolean) */ NUMBER_STRING_BOOLEAN, /** * (number,string) */ NUMBER_STRING, }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import com.google.common.collect.Maps; import com.google.javascript.rhino.ErrorReporter; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.jstype.RecordTypeBuilder.RecordProperty; import java.util.Map; import java.util.Set; import java.util.SortedMap; /** * A record (structural) type. * * Subtyping: The subtyping of a record type is defined via structural * comparison of a record type's properties. For example, a record * type of the form { a : TYPE_1 } is a supertype of a record type * of the form { b : TYPE_2, a : TYPE_1 } because B can be assigned to * A and matches all constraints. Similarly, a defined type can be assigned * to a record type so long as that defined type matches all property * constraints of the record type. A record type of the form { a : A, b : B } * can be assigned to a record of type { a : A }. * */ public class RecordType extends PrototypeObjectType { private static final long serialVersionUID = 1L; private final SortedMap<String, JSType> properties = Maps.newTreeMap(); private boolean isFrozen = false; /** * Creates a record type. * * @param registry The type registry under which this type lives. * @param properties A map of all the properties of this record type. * @throws IllegalStateException if the {@code RecordProperty} associated * with a property is null. */ RecordType(JSTypeRegistry registry, Map<String, RecordProperty> properties) { super(registry, null, null); for (String property : properties

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>.keySet()) { RecordProperty prop = properties.get(property); if (prop == null) { throw new IllegalStateException( "RecordProperty associated with a property should not be null!"); } defineDeclaredProperty(property, prop.getType(), false, prop.getPropertyNode()); } // Freeze the record type. isFrozen = true; } @Override public boolean isEquivalentTo(JSType other) { if (!(other instanceof RecordType)) { return false; } // Compare properties. RecordType otherRecord = (RecordType) other; Set<String> keySet = properties.keySet(); Map<String, JSType> otherProps = otherRecord.properties; if (!otherProps.keySet().equals(keySet)) { return false; } for (String key : keySet) { if (!otherProps.get(key).isEquivalentTo(properties.get(key))) { return false; } } return true; } @Override public ObjectType getImplicitPrototype() { return registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE); } @Override boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns, Node propertyNode) { if (isFrozen) { return false; } if (!inferred) { properties.put(propertyName, type); } return super.defineProperty(propertyName, type, inferred, inExterns, propertyNode); } @Override public JSType getLeastSupertype(JSType that) { if (!that.isRecordType()) { return super.getLeastSupertype(that); } RecordType thatRecord = (RecordType) that; RecordTypeBuilder builder = new RecordTypeBuilder(registry); // The least supertype consist of those properties of the record // type that both record types hold in common both by name and // type of the properties themselves. for (String property : properties.keySet()) { if (thatRecord.hasProperty(property) && thatRecord.getPropertyType(property).isEquivalentTo( getPropertyType(property))) { builder.addProperty(property, getPropertyType(property), getPropertyNode(property)); } } return builder.build(); } @Override public JSType getGreatestSubtype(JSType that) { if (that.isRecordType()) { RecordType thatRecord = (RecordType) that; RecordTypeBuilder builder = new RecordTypeBuilder(registry); // The greatest subtype consists of those *unique* properties of both // record types. If any property conflicts, then the NO_TYPE type // is returned. for (String property : properties.keySet()) { if (thatRecord.hasProperty(property) && !thatRecord.getPropertyType(property).isEquivalentTo( getPropertyType(property))) { return registry.getNativeObjectType(JSTypeNative.NO_TYPE); } builder.addProperty(property, getPropertyType(property), getPropertyNode(property)); } for (String property : thatRecord.properties.keySet()) { if (!hasProperty(property)) { builder.addProperty(property, thatRecord.getPropertyType(property), thatRecord.getPropertyNode(property)); } } return builder.build(); } JSType greatestSubtype = super.getGreatestSubtype(that); if (greatestSubtype.isNoObjectType() && !that.isNoObjectType()) { // In this branch, the other type is some object type. We find // the greatest subtype with the following algorithm: // 1) For each property "x" of this record type, take the union //

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> of all classes with a property "x" with a compatible property type. // and which are a subtype of {@code that}. // 2) Take the intersection of all of these unions. for (Map.Entry<String, JSType> entry : properties.entrySet()) { String propName = entry.getKey(); JSType propType = entry.getValue(); UnionTypeBuilder builder = new UnionTypeBuilder(registry); for (ObjectType alt : registry.getEachReferenceTypeWithProperty(propName)) { JSType altPropType = alt.getPropertyType(propName); if (altPropType != null && !alt.isEquivalentTo(this) && alt.isSubtype(that) && (propType.isUnknownType() || altPropType.isUnknownType() || altPropType.isEquivalentTo(propType))) { builder.addAlternate(alt); } } greatestSubtype = greatestSubtype.getLeastSupertype(builder.build()); } } return greatestSubtype; } @Override public boolean isRecordType() { return true; } @Override public boolean isSubtype(JSType that) { if (JSType.isSubtype(this, that)) { return true; } // Top of the record types is the empty record, or OBJECT_TYPE. if (registry.getNativeObjectType( JSTypeNative.OBJECT_TYPE).isSubtype(that)) { return true; } // A type is a subtype of a record type if it itself is a record // type and it has at least the same members as the parent record type // with the same types. if (!that.isRecordType()) { return false; } return RecordType.isSubtype(this, (RecordType) that); } /** Determines if typeA is a subtype of typeB */ static boolean isSubtype(ObjectType typeA, RecordType typeB) { // typeA is a subtype of record type typeB iff: // 1) typeA has all the properties declared in typeB. // 2) And for each property of typeB, // 2a) if the property of typeA is declared, it must be equal // to the type of the property of typeB, // 2b) otherwise, it must be a subtype of the property of typeB. // // To figure out why this is true, consider the following pseudo-code: // /** @type {{a: (Object,null)}} */ var x; // /** @type {{a: !Object}} */ var y; // var z = {a: {}}; // x.a = null; // // y cannot be assigned to x, because line 4 would violate y's declared // properties. But z can be assigned to x. Even though z and y are the // same type, the properties of z are inferred--and so an assignment // to the property of z would not violate any restrictions on it. for (String property : typeB.properties.keySet()) { if (!typeA.hasProperty(property)) { return false; } JSType propA = typeA.getPropertyType(property); JSType propB = typeB.getPropertyType(property); if (!propA.isUnknownType() && !propB.isUnknownType()) { if (typeA.isPropertyTypeDeclared(property)) { if (!propA.isEquivalentTo(propB)) { return false; } } else { if (!propA.isSubtype(propB)) { return false; } } } } return true; }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import static com.google.javascript.rhino.jstype.JSTypeNative.ALL_TYPE; /** * This type is for built-in error constructors. */ class ErrorFunctionType extends FunctionType { private static final long serialVersionUID = 1L; ErrorFunctionType(JSTypeRegistry registry, String name) { super( registry, name, null, registry.createArrowType( registry.createOptionalParameters( registry.getNativeType(ALL_TYPE), registry.getNativeType(ALL_TYPE), registry.getNativeType(ALL_TYPE)), null), null, null, true, true); // NOTE(nicksantos): Errors have the weird behavior in that they can // be called as functions, and they will return instances of themselves. // Error('x') instanceof Error => true // // In user-defined types, we would deal with this case by creating // a NamedType with the name "Error" and then resolve it later. // // For native types, we don't really want the native types to // depend on type-resolution. So we just set the return type manually // at the end of construction. // // There's similar logic in JSTypeRegistry for Array and RegExp. getInternalArrowType().returnType = getInstanceType(); } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN; import com.google.javascript.rhino.ErrorReporter; /** * All type, representing all values. */ public final class AllType extends JSType { private static final long serialVersionUID = 1L; AllType(JSTypeRegistry registry) { super(registry); } /** * The All type is the greatest type (top) and is never a subtype of * another except itself or the Unknown type or a named alias. * @return {@code this.isEquivalentTo(that)} */ @Override public boolean isSubtype(JSType that) { return JSType.isSubtype(this, that); } @Override public boolean isAllType() { return true; } @Override public boolean matchesStringContext() { // Be lenient. return true; } @Override public boolean matchesObjectContext() { // Be lenient. return true; } @Override public boolean canBeCalled() { return false; } @Override public TernaryValue testForEquality(JSType that) { return UNKNOWN; } @Override public String toString() { return "*"; } @Override public String getDisplayName() { return "<Any Type>"; } @Override public boolean hasDisplayName() { return true; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseAllType(); } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.BOTH; } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { return this;

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import static com.google.javascript.rhino.jstype.JSTypeNative.ALL_TYPE; import static com.google.javascript.rhino.jstype.JSTypeNative.CHECKED_UNKNOWN_TYPE; import static com.google.javascript.rhino.jstype.JSTypeNative.NO_TYPE; import static com.google.javascript.rhino.jstype.JSTypeNative.UNKNOWN_TYPE; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.javascript.rhino.jstype.UnionType; import java.io.Serializable; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; /** * A builder for union types. * * @author nicksantos@google.com (Nick Santos) */ class UnionTypeBuilder implements Serializable { private static final long serialVersionUID = 1L; // If the best we can do is say "this object is one of twenty things", // then we should just give up and admit that we have no clue. private static final int MAX_UNION_SIZE = 20; private final JSTypeRegistry registry; private final List<JSType> alternates = Lists.newArrayList(); private boolean isAllType = false; private boolean isNativeUnknownType = false; private boolean areAllUnknownsChecked = true; // Memoize the result, in case build() is called multiple times. private JSType result = null; UnionTypeBuilder(JSTypeRegistry registry) { this.registry = registry; } Iterable<JSType> getAlternates() {

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> JSType specialCaseType = reduceAlternatesWithoutUnion(); if (specialCaseType != null) { return ImmutableList.of(specialCaseType); } return alternates; } /** * Adds an alternate to the union type under construction. Returns this * for easy chaining. */ UnionTypeBuilder addAlternate(JSType alternate) { // build() returns the bottom type by default, so we can // just bail out early here. if (alternate.isNoType()) { return this; } isAllType = isAllType || alternate.isAllType(); boolean isAlternateUnknown = alternate instanceof UnknownType; isNativeUnknownType = isNativeUnknownType || isAlternateUnknown; if (isAlternateUnknown) { areAllUnknownsChecked = areAllUnknownsChecked && alternate.isCheckedUnknownType(); } if (!isAllType && !isNativeUnknownType) { if (alternate instanceof UnionType) { UnionType union = (UnionType) alternate; for (JSType unionAlt : union.getAlternates()) { addAlternate(unionAlt); } } else { if (alternates.size() > MAX_UNION_SIZE) { return this; } // Look through the alternates we've got so far, // and check if any of them are duplicates of // one another. Iterator<JSType> it = alternates.iterator(); while (it.hasNext()) { JSType current = it.next(); // Unknown and NoResolved types may just be names that haven't // been resolved yet. So keep these in the union, and just use // equality checking for simple de-duping. if (alternate.isUnknownType() || current.isUnknownType() || alternate.isNoResolvedType() || current.isNoResolvedType()) { if (alternate.isEquivalentTo(current)) { // Alternate is unnecessary. return this; } } else { if (alternate.isSubtype(current)) { // Alternate is unnecessary. return this; } else if (current.isSubtype(alternate)) { // Alternate makes current obsolete it.remove(); } } } alternates.add(alternate); result = null; // invalidate the memoized result } } else { result = null; } return this; } /** * Reduce the alternates into a non-union type. * If the alternates can't be accurately represented with a non-union * type, return null. */ private JSType reduceAlternatesWithoutUnion() { if (isAllType) { return registry.getNativeType(ALL_TYPE); } else if (isNativeUnknownType) { if (areAllUnknownsChecked) { return registry.getNativeType(CHECKED_UNKNOWN_TYPE); } else { return registry.getNativeType(UNKNOWN_TYPE); } } else { int size = alternates.size(); if (size > MAX_UNION_SIZE) { return registry.getNativeType(UNKNOWN_TYPE); } else if (size > 1) { return null; } else if (size == 1) { return alternates.iterator().next(); } else { return registry.getNativeType(NO_TYPE); } } } /** * Creates a union. * @return A UnionType if it has two or more alternates, the * only alternate if it has one and otherwise {@code NO_TYPE}. */ JSType build() { if (result == null) { result = reduceAlternatesWithoutUnion(); if

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> (result == null) { result = new UnionType(registry, getAlternateListCopy()); } } return result; } private static final Comparator<JSType> typeSorter = new Comparator<JSType>() { @Override public int compare(JSType a, JSType b) { return b.hashCode() - a.hashCode(); } }; private Collection<JSType> getAlternateListCopy() { // TODO(nicksantos): Until we're at a place where we're no longer // using java's built-in equals to test type equivalence, we need // hash codes to be the same. So the alternates need to be sorted. Collections.sort(alternates, typeSorter); return ImmutableList.copyOf(alternates); } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import com.google.javascript.rhino.ErrorReporter; import com.google.javascript.rhino.Node; import java.util.Set; /** * The type of individual elements of an enum type * (see {@link EnumType}). */ public class EnumElementType extends ObjectType { private static final long serialVersionUID = 1L; /** * The primitive type this enum element type wraps. For instance, in * the following code defining the {@code LOCAL_CODES} enum * <pre>var LOCAL_CODES = {A: 3, B: 9, C: 8}</pre> * the primitive type of the the constants is {@code number}. */ private JSType primitiveType; // The primitive type, if it is an object. private ObjectType primitiveObjectType; private final String name; EnumElementType(JSTypeRegistry registry, JSType elementType, String name) { super(registry); this.primitiveType = elementType; this.primitiveObjectType = elementType.toObjectType(); this.name = name; } @Override public boolean isEnumElementType() { return true; } @Override public boolean matchesNumberContext() { return primitiveType.matchesNumberContext(); } @Override public boolean matchesStringContext() { return primitiveType.matchesStringContext(); } @Override public boolean matchesObjectContext() { return primitiveType.matchesObjectContext(); } @Override public boolean canBeCalled() { return primitiveType.canBeCalled(); } @Override public boolean isObject() { return primitiveType.isObject(); } @Override public TernaryValue testForEquality(JSType that) { return primitiveType.testForEquality(that); } /** *

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> This predicate determines whether objects of this type can have the null * value, and therefore can appear in contexts where null is expected. * * @return true for everything but Number and Boolean types. */ @Override public boolean isNullable() { return primitiveType.isNullable(); } @Override public boolean isNominalType() { return hasReferenceName(); } @Override public boolean isEquivalentTo(JSType that) { if (this == that) { return true; } else if (this.isNominalType()) { ObjectType thatObj = ObjectType.cast(that); if (thatObj != null && thatObj.isNominalType()) { return getReferenceName().equals(thatObj.getReferenceName()); } } return false; } /** * If this is equal to a NamedType object, its hashCode must be equal * to the hashCode of the NamedType object. */ @Override public int hashCode() { if (hasReferenceName()) { return getReferenceName().hashCode(); } else { return super.hashCode(); } } @Override public String toString() { return getReferenceName() + ".<" + primitiveType + ">"; } @Override public String getReferenceName() { return name; } @Override public boolean hasReferenceName() { return true; } @Override public boolean isSubtype(JSType that) { if (JSType.isSubtype(this, that)) { return true; } else { return primitiveType.isSubtype(that); } } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseEnumElementType(this); } @Override boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns, Node propertyNode) { // nothing return true; } @Override public boolean isPropertyTypeDeclared(String propertyName) { return primitiveObjectType == null ? false : primitiveObjectType.isPropertyTypeDeclared(propertyName); } @Override public boolean isPropertyTypeInferred(String propertyName) { return primitiveObjectType == null ? false : primitiveObjectType.isPropertyTypeInferred(propertyName); } @Override public ObjectType getImplicitPrototype() { return null; } @Override public int getPropertiesCount() { return primitiveObjectType == null ? 0 : primitiveObjectType.getPropertiesCount(); } @Override void collectPropertyNames(Set<String> props) { if (primitiveObjectType != null) { primitiveObjectType.collectPropertyNames(props); } } @Override public JSType findPropertyType(String propertyName) { return primitiveType.findPropertyType(propertyName); } @Override public JSType getPropertyType(String propertyName) { return primitiveObjectType == null ? getNativeType(JSTypeNative.UNKNOWN_TYPE) : primitiveObjectType.getPropertyType(propertyName); } @Override public boolean hasProperty(String propertyName) { return primitiveObjectType == null ? false : primitiveObjectType.hasProperty(propertyName); } @Override public FunctionType getConstructor() { return primitiveObjectType == null ? null : primitiveObjectType.getConstructor(); } @Override public JSType autoboxesTo() { return primitiveType.autoboxesTo(); } /** * Gets the primitive type of this enum element. */ public JSType getPrimitiveType() { return primitiveType; } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { primitiveType = primitiveType.resolve(t, scope); primitiveObjectType = (ObjectType) safeResolve

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> We a) want to * make sure that the type information specified in the externs file * matches what is in the registry and b) annotate the externs with * the {@link JSType} from the registry so that there are not two * separate JSType objects for one type. */ private FunctionType getOrCreateConstructor() { FunctionType fnType = typeRegistry.createConstructorType( fnName, sourceNode, parametersNode, returnType); JSType existingType = typeRegistry.getType(fnName); if (existingType != null) { boolean isInstanceObject = existingType instanceof InstanceObjectType; if (isInstanceObject || fnName.equals("Function")) { FunctionType existingFn = isInstanceObject ? ((InstanceObjectType) existingType).getConstructor() : typeRegistry.getNativeFunctionType(FUNCTION_FUNCTION_TYPE); if (existingFn.getSource() == null) { existingFn.setSource(sourceNode); } if (!existingFn.hasEqualCallType(fnType)) { reportWarning(TYPE_REDEFINITION, fnName, fnType.toString(), existingFn.toString()); } return existingFn; } else { // We fall through and return the created type, even though it will fail // to register. We have no choice as we have to return a function. We // issue an error elsewhere though, so the user should fix it. } } maybeSetBaseType(fnType); if (getScopeDeclaredIn().isGlobal() && !fnName.isEmpty()) { typeRegistry.declareType(fnName, fnType.getInstanceType()); } return fnType; } private void reportWarning(DiagnosticType warning, String ... args) { compiler.report(JSError.make(sourceName, errorRoot, warning, args)); } private void reportError(DiagnosticType error, String ... args) { compiler.report(JSError.make(sourceName, errorRoot, error, args)); } /** * Determines whether the given jsdoc info declares a function type. */ static boolean isFunctionTypeDeclaration(JSDocInfo info) { return info.getParameterCount() > 0 || info.hasReturnType() || info.hasThisType() || info.isConstructor() || info.isInterface(); } /** * The scope that we should declare this function in, if it needs * to be declared in a scope. Notice that TypedScopeCreator takes * care of most scope-declaring. */ private Scope getScopeDeclaredIn() { int dotIndex = fnName.indexOf("."); if (dotIndex != -1) { String rootVarName = fnName.substring(0, dotIndex); Var rootVar = scope.getVar(rootVarName); if (rootVar != null) { return rootVar.getScope(); } } return scope; } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> = callName.getNext(); if (!typeNode.isQualifiedName()) { return null; } Node objectNode = typeNode.getNext(); if (objectNode.getType() != Token.OBJECTLIT) { t.getCompiler().report(JSError.make(t.getSourceName(), callNode, OBJECTLIT_EXPECTED)); return null; } return new ObjectLiteralCast(typeNode.getQualifiedName(), typeNode.getNext()); } @Override public boolean isOptionalParameter(Node parameter) { return false; } @Override public boolean isVarArgsParameter(Node parameter) { return false; } @Override public boolean isPrivate(String name) { return false; } @Override public Collection<AssertionFunctionSpec> getAssertionFunctions() { return ImmutableList.<AssertionFunctionSpec>of( new AssertionFunctionSpec("goog.asserts.assert"), new AssertionFunctionSpec("goog.asserts.assertNumber", JSTypeNative.NUMBER_TYPE), new AssertionFunctionSpec("goog.asserts.assertString", JSTypeNative.STRING_TYPE), new AssertionFunctionSpec("goog.asserts.assertFunction", JSTypeNative.FUNCTION_INSTANCE_TYPE), new AssertionFunctionSpec("goog.asserts.assertObject", JSTypeNative.OBJECT_TYPE), new AssertionFunctionSpec("goog.asserts.assertArray", JSTypeNative.ARRAY_TYPE), // TODO(agrieve): It would be better if this could make the first // parameter the type of the second parameter. new AssertionFunctionSpec("goog.asserts.assertInstanceof", JSTypeNative.OBJECT_TYPE) ); } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import static com.google.javascript.rhino.jstype.TernaryValue.FALSE; import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN; /** * Number type. */ public class NumberType extends ValueType { private static final long serialVersionUID = 1L; NumberType(JSTypeRegistry registry) { super(registry); } @Override public boolean isNullable() { return false; } @Override public TernaryValue testForEquality(JSType that) { TernaryValue result = super.testForEquality(that); if (result != null) { return result; } if (that.isUnknownType() || that.isSubtype( getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN))) { return UNKNOWN; } return FALSE; } @Override public boolean isNumberValueType() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public boolean matchesObjectContext() { // TODO(user): Revisit this for ES4, which is stricter. return true; } @Override public String toString() { return getDisplayName(); } @Override public String getDisplayName() { return "number"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.BOTH; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseNumberType(); } @Override public JSType autoboxesTo() { return getNativeType(JSTypeNative.NUMBER_OBJECT_TYPE); }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import com.google.common.base.Preconditions; import com.google.javascript.rhino.Node; /** * An object type that is an instance of some function constructor. */ public final class InstanceObjectType extends PrototypeObjectType { private static final long serialVersionUID = 1L; private final FunctionType constructor; InstanceObjectType(JSTypeRegistry registry, FunctionType constructor) { this(registry, constructor, false); } InstanceObjectType(JSTypeRegistry registry, FunctionType constructor, boolean isNativeType) { super(registry, null, null, isNativeType); Preconditions.checkNotNull(constructor); this.constructor = constructor; } @Override public String getReferenceName() { return getConstructor().getReferenceName(); } @Override public boolean hasReferenceName() { return getConstructor().hasReferenceName(); } @Override public ObjectType getImplicitPrototype() { return getConstructor().getPrototype(); } @Override public FunctionType getConstructor() { return constructor; } @Override boolean defineProperty(String name, JSType type, boolean inferred, boolean inExterns, Node propertyNode) { ObjectType proto = getImplicitPrototype(); if (proto != null && proto.hasOwnDeclaredProperty(name)) { return false; } return super.defineProperty(name, type, inferred, inExterns, propertyNode); } @Override public String toString() { if (constructor.hasReferenceName()) { return constructor.getReferenceName(); } else { return super.toString(); } } @Override boolean isTheObjectType() { return getConstructor().isNative() && "Object".equals(getReferenceName()); } @Override public boolean isInstanceType() { return true; }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> };", "inconsistent return type\n" + "found : (number|string)\n" + "required: string"); } public void testResolutionViaRegistry4() throws Exception { testTypes("/** @constructor */ u.A = function() {};\n" + "/**\n* @constructor\n* @extends {u.A}\n*/\nu.A.A = function() {}\n;" + "/**\n* @constructor\n* @extends {u.A}\n*/\nu.A.B = function() {};\n" + "var ab = new u.A.B();\n" + "/** @type {!u.A} */ var a = ab;\n" + "/** @type {!u.A.A} */ var aa = ab;\n", "initializing variable\n" + "found : u.A.B\n" + "required: u.A.A"); } public void testResolutionViaRegistry5() throws Exception { Node n = parseAndTypeCheck("/** @constructor */ u.T = function() {}; u.T"); JSType type = n.getLastChild().getLastChild().getJSType(); assertFalse(type.isUnknownType()); assertTrue(type instanceof FunctionType); assertEquals("u.T", ((FunctionType) type).getInstanceType().getReferenceName()); } public void testGatherProperyWithoutAnnotation1() throws Exception { Node n = parseAndTypeCheck("/** @constructor */ var T = function() {};" + "/** @type {!T} */var t; t.x; t;"); JSType type = n.getLastChild().getLastChild().getJSType(); assertFalse(type.isUnknownType()); assertTrue(type instanceof ObjectType); ObjectType objectType = (ObjectType) type; assertFalse(objectType.hasProperty("x")); assertEquals( Lists.newArrayList(objectType), registry.getTypesWithProperty("x")); } public void testGatherProperyWithoutAnnotation2() throws Exception { TypeCheckResult ns = parseAndTypeCheckWithScope("/** @type {!Object} */var t; t.x; t;"); Node n = ns.root; Scope s = ns.scope; JSType type = n.getLastChild().getLastChild().getJSType(); assertFalse(type.isUnknownType()); assertEquals(type, OBJECT_TYPE); assertTrue(type instanceof ObjectType); ObjectType objectType = (ObjectType) type; assertFalse(objectType.hasProperty("x")); assertEquals( Lists.newArrayList(OBJECT_TYPE), registry.getTypesWithProperty("x")); } public void testFunctionMasksVariableBug() throws Exception { testTypes("var x = 4; var f = function x(b) { return b ? 1 : x(true); };", "function x masks variable (IE bug)"); } public void testDfa1() throws Exception { testTypes("var x = null;\n x = 1;\n /** @type number */ var y = x;"); } public void testDfa2() throws Exception { testTypes("function u() {}\n" + "/** @return {number} */ function f() {\nvar x = 'todo';\n" + "if (u()) { x = 1; } else { x = 2; } return x;\n}"); } public void testDfa3() throws Exception { testTypes("function u() {}\n" + "/** @return {number} */ function f() {\n" + "/** @type {number|string} */ var x = 'todo';

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> parameter\n" + "found : number\n" + "required: string"); } public void testLends1() throws Exception { testTypes( "function extend(x, y) {}" + "/** @constructor */ function Foo() {}" + "extend(Foo, /** @lends */ ({bar: 1}));", "Parse error. missing object name in @lends tag"); } public void testLends2() throws Exception { testTypes( "function extend(x, y) {}" + "/** @constructor */ function Foo() {}" + "extend(Foo, /** @lends {Foob} */ ({bar: 1}));", "Variable Foob not declared before @lends annotation."); } public void testLends3() throws Exception { testTypes( "function extend(x, y) {}" + "/** @constructor */ function Foo() {}" + "extend(Foo, {bar: 1});" + "alert(Foo.bar);", "Property bar never defined on Foo"); } public void testLends4() throws Exception { testTypes( "function extend(x, y) {}" + "/** @constructor */ function Foo() {}" + "extend(Foo, /** @lends {Foo} */ ({bar: 1}));" + "alert(Foo.bar);"); } public void testLends5() throws Exception { testTypes( "function extend(x, y) {}" + "/** @constructor */ function Foo() {}" + "extend(Foo, {bar: 1});" + "alert((new Foo()).bar);", "Property bar never defined on Foo"); } public void testLends6() throws Exception { testTypes( "function extend(x, y) {}" + "/** @constructor */ function Foo() {}" + "extend(Foo, /** @lends {Foo.prototype} */ ({bar: 1}));" + "alert((new Foo()).bar);"); } public void testLends7() throws Exception { testTypes( "function extend(x, y) {}" + "/** @constructor */ function Foo() {}" + "extend(Foo, /** @lends {Foo.prototype|Foo} */ ({bar: 1}));", "Parse error. expected closing }"); } public void testLends8() throws Exception { testTypes( "function extend(x, y) {}" + "/** @type {number} */ var Foo = 3;" + "extend(Foo, /** @lends {Foo} */ ({bar: 1}));", "May only lend properties to object types. Foo has type number."); } public void testLends9() throws Exception { testClosureTypesMultipleWarnings( "function extend(x, y) {}" + "/** @constructor */ function Foo() {}" + "extend(Foo, /** @lends {!Foo} */ ({bar: 1}));", Lists.newArrayList( "Parse error. expected closing }", "Parse error. missing object name in @lends tag")); } public void testDeclaredNativeTypeEquality() throws Exception { Node n = parseAndTypeCheck("/** @constructor */ function Object() {};"); assertEquals(registry.getNativeType(JSTypeNative.OBJECT_FUNCTION_TYPE), n.getFirstChild().getJSType()); } public void testUndefinedVar() throws Exception { Node n = parseAndTypeCheck("var undefined;"); assertEquals(registry.getNativeType(JSTypeNative.VOID_

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>TYPE), n.getFirstChild().getFirstChild().getJSType()); } public void testFlowScopeBug1() throws Exception { Node n = parseAndTypeCheck("/** @param {number} a \n" + "* @param {number} b */\n" + "function f(a, b) {\n" + "/** @type number */" + "var i = 0;" + "for (; (i + a) < b; ++i) {}}"); // check the type of the add node for i + f assertEquals(registry.getNativeType(JSTypeNative.NUMBER_TYPE), n.getFirstChild().getLastChild().getLastChild().getFirstChild() .getNext().getFirstChild().getJSType()); } public void testFlowScopeBug2() throws Exception { Node n = parseAndTypeCheck("/** @constructor */ function Foo() {};\n" + "Foo.prototype.hi = false;" + "function foo(a, b) {\n" + " /** @type Array */" + " var arr;" + " /** @type number */" + " var iter;" + " for (iter = 0; iter < arr.length; ++ iter) {" + " /** @type Foo */" + " var afoo = arr[iter];" + " afoo;" + " }" + "}"); // check the type of afoo when referenced assertEquals(registry.createNullableType(registry.getType("Foo")), n.getLastChild().getLastChild().getLastChild().getLastChild() .getLastChild().getLastChild().getJSType()); } public void testAddSingletonGetter() { Node n = parseAndTypeCheck( "/** @constructor */ function Foo() {};\n" + "goog.addSingletonGetter(Foo);"); ObjectType o = (ObjectType) n.getFirstChild().getJSType(); assertEquals("function (): Foo", o.getPropertyType("getInstance").toString()); assertEquals("Foo", o.getPropertyType("instance_").toString()); } public void testTypeCheckStandaloneAST() throws Exception { Node n = compiler.parseTestCode("function Foo() { }"); typeCheck(n); TypedScopeCreator scopeCreator = new TypedScopeCreator(compiler); Scope topScope = scopeCreator.createScope(n, null); Node second = compiler.parseTestCode("new Foo"); Node externs = new Node(Token.BLOCK); Node externAndJsRoot = new Node(Token.BLOCK, externs, second); externAndJsRoot.setIsSyntheticBlock(true); new TypeCheck( compiler, new SemanticReverseAbstractInterpreter( compiler.getCodingConvention(), registry), registry, topScope, scopeCreator, CheckLevel.WARNING, CheckLevel.OFF) .process(null, second); assertEquals(1, compiler.getWarningCount()); assertEquals("cannot instantiate non-constructor", compiler.getWarnings()[0].description); } public void testUpdateParameterTypeOnClosure() throws Exception { testTypes( "/**\n" + "* @constructor\n" + "* @param {*=} opt_value\n" + "* @return {?}\n" + "*/\n" + "function Object(opt_value) {}\n" + "/**\n" + "* @constructor\n" + "* @param {...*} var_args\n" + "*/\n" + "function Function(var_args) {}\n" + "/**\n" + "* @type {Function}\n" + "*/\n"

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> testFunctionLiteralUnreadThisArgument() throws Exception { testTypes("" + "/**\n" + " * @param {function(this:T, ...)?} fn\n" + " * @param {?T} opt_obj\n" + " * @template T\n" + " */\n" + "function baz(fn, opt_obj) {}\n" + "baz(function() {}, {});", "Function literal argument does not refer to bound this argument"); } public void testFunctionLiteralUnreadNullThisArgument() throws Exception { testTypes("" + "/**\n" + " * @param {function(this:T, ...)?} fn\n" + " * @param {?T} opt_obj\n" + " * @template T\n" + " */\n" + "function baz(fn, opt_obj) {}\n" + "baz(function() {}, null);"); } public void testActiveXObject() throws Exception { testTypes( "/** @type {Object} */ var x = new ActiveXObject();" + "/** @type { {impossibleProperty} } */ var y = new ActiveXObject();"); } private void checkObjectType(ObjectType objectType, String propertyName, JSType expectedType) { assertTrue("Expected " + objectType.getReferenceName() + " to have property " + propertyName, objectType.hasProperty(propertyName)); assertEquals("Expected " + objectType.getReferenceName() + "'s property " + propertyName + " to have type " + expectedType, expectedType, objectType.getPropertyType(propertyName)); } private void testTypes(String js) throws Exception { testTypes(js, (String) null); } private void testTypes(String js, String description) throws Exception { testTypes(js, description, false); } private void testTypes(String js, DiagnosticType type) throws Exception { testTypes(js, type.format(), false); } private void testClosureTypes(String js, String description) throws Exception { testClosureTypesMultipleWarnings(js, description == null ? null : Lists.newArrayList(description)); } private void testClosureTypesMultipleWarnings( String js, List<String> descriptions) throws Exception { Node n = compiler.parseTestCode(js); Node externs = new Node(Token.BLOCK); Node externAndJsRoot = new Node(Token.BLOCK, externs, n); externAndJsRoot.setIsSyntheticBlock(true); assertEquals("parsing error: " + Joiner.on(", ").join(compiler.getErrors()), 0, compiler.getErrorCount()); // For processing goog.addDependency for forward typedefs. new ProcessClosurePrimitives(compiler, CheckLevel.ERROR, true) .process(null, n); CodingConvention convention = compiler.getCodingConvention(); new TypeCheck(compiler, new ClosureReverseAbstractInterpreter( convention, registry).append( new SemanticReverseAbstractInterpreter( convention, registry)) .getFirst(), registry) .processForTesting(null, n); assertEquals(0, compiler.getErrorCount()); if (descriptions == null) { assertEquals( "unexpected warning(s) : " + Joiner.on(", ").join(compiler.getWarnings()), 0, compiler.getWarningCount()); } else { assertEquals( "unexpected warning(s) : " + Joiner.on(", ").join(compiler.getWarnings()), descriptions.size(), compiler.getWarningCount()); for (int i = 0; i < descriptions.size(); i++)

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> { assertEquals(descriptions.get(i), compiler.getWarnings()[i].description); } } } void testTypes(String js, String description, boolean isError) throws Exception { testTypes(DEFAULT_EXTERNS, js, description, isError); } void testTypes(String externs, String js, String description, boolean isError) throws Exception { Node n = parseAndTypeCheck(externs, js); JSError[] errors = compiler.getErrors(); if (description != null && isError) { assertTrue("expected an error", errors.length > 0); assertEquals(description, errors[0].description); errors = Arrays.asList(errors).subList(1, errors.length).toArray( new JSError[errors.length - 1]); } if (errors.length > 0) { fail("unexpected error(s):\n" + Joiner.on("\n").join(errors)); } JSError[] warnings = compiler.getWarnings(); if (description != null && !isError) { assertTrue("expected a warning", warnings.length > 0); assertEquals(description, warnings[0].description); warnings = Arrays.asList(warnings).subList(1, warnings.length).toArray( new JSError[warnings.length - 1]); } if (warnings.length > 0) { fail("unexpected warnings(s):\n" + Joiner.on("\n").join(warnings)); } } /** * Parses and type checks the JavaScript code. */ private Node parseAndTypeCheck(String js) { return parseAndTypeCheck(DEFAULT_EXTERNS, js); } private Node parseAndTypeCheck(String externs, String js) { return parseAndTypeCheckWithScope(externs, js).root; } /** * Parses and type checks the JavaScript code and returns the Scope used * whilst type checking. */ private TypeCheckResult parseAndTypeCheckWithScope(String js) { return parseAndTypeCheckWithScope(DEFAULT_EXTERNS, js); } private TypeCheckResult parseAndTypeCheckWithScope( String externs, String js) { compiler.init( Lists.newArrayList(JSSourceFile.fromCode("[externs]", externs)), Lists.newArrayList(JSSourceFile.fromCode("[testcode]", js)), compiler.getOptions()); Node n = compiler.getInput("[testcode]").getAstRoot(compiler); Node externsNode = compiler.getInput("[externs]").getAstRoot(compiler); Node externAndJsRoot = new Node(Token.BLOCK, externsNode, n); externAndJsRoot.setIsSyntheticBlock(true); assertEquals("parsing error: " + Joiner.on(", ").join(compiler.getErrors()), 0, compiler.getErrorCount()); Scope s = makeTypeCheck().processForTesting(externsNode, n); return new TypeCheckResult(n, s); } private Node typeCheck(Node n) { Node externsNode = new Node(Token.BLOCK); Node externAndJsRoot = new Node(Token.BLOCK, externsNode, n); externAndJsRoot.setIsSyntheticBlock(true); makeTypeCheck().processForTesting(null, n); return n; } private TypeCheck makeTypeCheck() { return new TypeCheck( compiler, new SemanticReverseAbstractInterpreter( compiler.getCodingConvention(), registry), registry, reportMissingOverrides, CheckLevel.OFF); } void testTypes(String js, String[] warnings) throws Exception { Node n =

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import static com.google.javascript.rhino.jstype.TernaryValue.FALSE; import static com.google.javascript.rhino.jstype.TernaryValue.TRUE; import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN; /** * Null type. */ public final class NullType extends ValueType { private static final long serialVersionUID = 1L; NullType(JSTypeRegistry registry) { super(registry); } @Override public boolean isNullType() { return true; } @Override public boolean isNullable() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesObjectContext() { return false; } @Override public boolean matchesStringContext() { return true; } @Override public JSType restrictByNotNullOrUndefined() { return registry.getNativeType(JSTypeNative.NO_TYPE); } @Override public TernaryValue testForEquality(JSType that) { TernaryValue result = super.testForEquality(that); if (result != null) { return result; } if (that.isNullType() || that.isVoidType()) { return TRUE; } if (that.isUnknownType() || that.isNullable()) { return UNKNOWN; } return FALSE; } @Override public String toString() { return getDisplayName(); } @Override public String getDisplayName() { return "null"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.FALSE; } @Override public <T> T visit(Visitor<T> visitor)

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import com.google.javascript.rhino.jstype.ObjectType; /** * Represents the prototype of a {@link FunctionType}. * @author nicksantos@google.com (Nick Santos) */ public class FunctionPrototypeType extends PrototypeObjectType { private static final long serialVersionUID = 1L; private final FunctionType ownerFunction; FunctionPrototypeType(JSTypeRegistry registry, FunctionType ownerFunction, ObjectType implicitPrototype, boolean isNative) { super(registry, null /* has no class name */, implicitPrototype, isNative); this.ownerFunction = ownerFunction; } FunctionPrototypeType(JSTypeRegistry registry, FunctionType ownerFunction, ObjectType implicitPrototype) { this(registry, ownerFunction, implicitPrototype, false); } @Override public String getReferenceName() { if (ownerFunction == null) { return "{...}.prototype"; } else { return ownerFunction.getReferenceName() + ".prototype"; } } @Override public boolean hasReferenceName() { return ownerFunction != null && ownerFunction.hasReferenceName(); } @Override public boolean isFunctionPrototypeType() { return true; } public FunctionType getOwnerFunction() { return ownerFunction; } @Override public Iterable<ObjectType> getCtorImplementedInterfaces() { return getOwnerFunction().getImplementedInterfaces(); } // The owner will always be a resolved type, so there's no need to set // the ownerFunction in resolveInternal. // (it would lead to infinite loops if we did). // JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope); }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> names in the expression point to * unknown types, then we create a proxy {@code NamedType} structure * until the type can be resolved. * * This is the legacy way of resolving ways, and may not exist in the * future. */ LAZY_NAMES, /** * Expressions and type names are evaluated aggressively. A warning * will be emitted if a type name fails to resolve to a real type. */ IMMEDIATE } private ResolveMode resolveMode = ResolveMode.LAZY_NAMES; /** * Constructs a new type registry populated with the built-in types. */ public JSTypeRegistry(ErrorReporter reporter) { this(reporter, false); } /** * Constructs a new type registry populated with the built-in types. */ public JSTypeRegistry( ErrorReporter reporter, boolean tolerateUndefinedValues) { this.reporter = reporter; nativeTypes = new JSType[JSTypeNative.values().length]; namesToTypes = new HashMap<String, JSType>(); resetForTypeCheck(); this.tolerateUndefinedValues = tolerateUndefinedValues; } /** * Set the current resolving mode of the type registry. * @see ResolveMode */ public void setResolveMode(ResolveMode mode) { this.resolveMode = mode; } ResolveMode getResolveMode() { return resolveMode; } public ErrorReporter getErrorReporter() { return reporter; } public boolean shouldTolerateUndefinedValues() { return tolerateUndefinedValues; } /** * Reset to run the TypeCheck pass. */ public void resetForTypeCheck() { typesIndexedByProperty.clear(); eachRefTypeIndexedByProperty.clear(); initializeBuiltInTypes(); namesToTypes.clear(); namespaces.clear(); initializeRegistry(); } private void initializeBuiltInTypes() { // These locals shouldn't be all caps. BooleanType BOOLEAN_TYPE = new BooleanType(this); registerNativeType(JSTypeNative.BOOLEAN_TYPE, BOOLEAN_TYPE); NullType NULL_TYPE = new NullType(this); registerNativeType(JSTypeNative.NULL_TYPE, NULL_TYPE); NumberType NUMBER_TYPE = new NumberType(this); registerNativeType(JSTypeNative.NUMBER_TYPE, NUMBER_TYPE); StringType STRING_TYPE = new StringType(this); registerNativeType(JSTypeNative.STRING_TYPE, STRING_TYPE); UnknownType UNKNOWN_TYPE = new UnknownType(this, false); registerNativeType(JSTypeNative.UNKNOWN_TYPE, UNKNOWN_TYPE); registerNativeType( JSTypeNative.CHECKED_UNKNOWN_TYPE, new UnknownType(this, true)); VoidType VOID_TYPE = new VoidType(this); registerNativeType(JSTypeNative.VOID_TYPE, VOID_TYPE); AllType ALL_TYPE = new AllType(this); registerNativeType(JSTypeNative.ALL_TYPE, ALL_TYPE); // Top Level Prototype (the One) // The initializations of TOP_LEVEL_PROTOTYPE and OBJECT_FUNCTION_TYPE // use each other's results, so at least one of them will get null // instead of an actual type; however, this seems to be benign. ObjectType TOP_LEVEL_PROTOTYPE = new FunctionPrototypeType(this, null, null, true); registerNativeType(JSTypeNative.TOP_LEVEL_PROTOTYPE, TOP_LEVEL_PROTOTYPE); // Object FunctionType OBJECT_FUNCTION_TYPE = new FunctionType(this, "Object", null, createArrowType(createOptionalParameters(ALL_TYPE), UNKNOWN

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>_TYPE), null, null, true, true); OBJECT_FUNCTION_TYPE.defineDeclaredProperty( "prototype", TOP_LEVEL_PROTOTYPE, true, null); registerNativeType(JSTypeNative.OBJECT_FUNCTION_TYPE, OBJECT_FUNCTION_TYPE); ObjectType OBJECT_PROTOTYPE = OBJECT_FUNCTION_TYPE.getPrototype(); registerNativeType(JSTypeNative.OBJECT_PROTOTYPE, OBJECT_PROTOTYPE); ObjectType OBJECT_TYPE = OBJECT_FUNCTION_TYPE.getInstanceType(); registerNativeType(JSTypeNative.OBJECT_TYPE, OBJECT_TYPE); // Function FunctionType FUNCTION_FUNCTION_TYPE = new FunctionType(this, "Function", null, createArrowType( createParametersWithVarArgs(ALL_TYPE), UNKNOWN_TYPE), null, null, true, true); FUNCTION_FUNCTION_TYPE.setPrototypeBasedOn(OBJECT_TYPE); registerNativeType( JSTypeNative.FUNCTION_FUNCTION_TYPE, FUNCTION_FUNCTION_TYPE); ObjectType FUNCTION_PROTOTYPE = FUNCTION_FUNCTION_TYPE.getPrototype(); registerNativeType(JSTypeNative.FUNCTION_PROTOTYPE, FUNCTION_PROTOTYPE); NoType NO_TYPE = new NoType(this); registerNativeType(JSTypeNative.NO_TYPE, NO_TYPE); NoObjectType NO_OBJECT_TYPE = new NoObjectType(this); registerNativeType(JSTypeNative.NO_OBJECT_TYPE, NO_OBJECT_TYPE); NoObjectType NO_RESOLVED_TYPE = new NoResolvedType(this); registerNativeType(JSTypeNative.NO_RESOLVED_TYPE, NO_RESOLVED_TYPE); // Array FunctionType ARRAY_FUNCTION_TYPE = new FunctionType(this, "Array", null, createArrowType(createParametersWithVarArgs(ALL_TYPE), null), null, null, true, true); ARRAY_FUNCTION_TYPE.getInternalArrowType().returnType = ARRAY_FUNCTION_TYPE.getInstanceType(); ObjectType arrayPrototype = ARRAY_FUNCTION_TYPE.getPrototype(); registerNativeType(JSTypeNative.ARRAY_FUNCTION_TYPE, ARRAY_FUNCTION_TYPE); ObjectType ARRAY_TYPE = ARRAY_FUNCTION_TYPE.getInstanceType(); registerNativeType(JSTypeNative.ARRAY_TYPE, ARRAY_TYPE); // Boolean FunctionType BOOLEAN_OBJECT_FUNCTION_TYPE = new FunctionType(this, "Boolean", null, createArrowType(createParameters(false, ALL_TYPE), BOOLEAN_TYPE), null, null, true, true); ObjectType booleanPrototype = BOOLEAN_OBJECT_FUNCTION_TYPE.getPrototype(); registerNativeType( JSTypeNative.BOOLEAN_OBJECT_FUNCTION_TYPE, BOOLEAN_OBJECT_FUNCTION_TYPE); ObjectType BOOLEAN_OBJECT_TYPE = BOOLEAN_OBJECT_FUNCTION_TYPE.getInstanceType(); registerNativeType(JSTypeNative.BOOLEAN_OBJECT_TYPE, BOOLEAN_OBJECT_TYPE); // Date FunctionType DATE_FUNCTION_TYPE = new FunctionType(this, "Date", null, createArrowType( createOptionalParameters(UNKNOWN_TYPE, UNKNOWN_TYPE, UNKNOWN_TYPE, UNKNOWN_TYPE, UNKNOWN_TYPE, UNKNOWN_TYPE, UNKNOWN_TYPE), STRING_TYPE), null, null, true, true); ObjectType datePrototype = DATE_FUNCTION_TYPE.getPrototype(); registerNativeType(JSTypeNative.DATE_FUNCTION_TYPE, DATE_FUNCTION_TYPE); ObjectType DATE_TYPE = DATE_FUNCTION_TYPE.getInstanceType(); registerNativeType(JSTypeNative.DATE_TYPE, DATE_TYPE); // Error FunctionType ERROR_FUNCTION_TYPE = new ErrorFunctionType(this, "Error"); registerNativeType(JSType

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>Native.ERROR_FUNCTION_TYPE, ERROR_FUNCTION_TYPE); ObjectType ERROR_TYPE = ERROR_FUNCTION_TYPE.getInstanceType(); registerNativeType(JSTypeNative.ERROR_TYPE, ERROR_TYPE); // EvalError FunctionType EVAL_ERROR_FUNCTION_TYPE = new ErrorFunctionType(this, "EvalError"); EVAL_ERROR_FUNCTION_TYPE.setPrototypeBasedOn(ERROR_TYPE); registerNativeType( JSTypeNative.EVAL_ERROR_FUNCTION_TYPE, EVAL_ERROR_FUNCTION_TYPE); ObjectType EVAL_ERROR_TYPE = EVAL_ERROR_FUNCTION_TYPE.getInstanceType(); registerNativeType(JSTypeNative.EVAL_ERROR_TYPE, EVAL_ERROR_TYPE); // RangeError FunctionType RANGE_ERROR_FUNCTION_TYPE = new ErrorFunctionType(this, "RangeError"); RANGE_ERROR_FUNCTION_TYPE.setPrototypeBasedOn(ERROR_TYPE); registerNativeType( JSTypeNative.RANGE_ERROR_FUNCTION_TYPE, RANGE_ERROR_FUNCTION_TYPE); ObjectType RANGE_ERROR_TYPE = RANGE_ERROR_FUNCTION_TYPE.getInstanceType(); registerNativeType(JSTypeNative.RANGE_ERROR_TYPE, RANGE_ERROR_TYPE); // ReferenceError FunctionType REFERENCE_ERROR_FUNCTION_TYPE = new ErrorFunctionType(this, "ReferenceError"); REFERENCE_ERROR_FUNCTION_TYPE.setPrototypeBasedOn(ERROR_TYPE); registerNativeType( JSTypeNative.REFERENCE_ERROR_FUNCTION_TYPE, REFERENCE_ERROR_FUNCTION_TYPE); ObjectType REFERENCE_ERROR_TYPE = REFERENCE_ERROR_FUNCTION_TYPE.getInstanceType(); registerNativeType(JSTypeNative.REFERENCE_ERROR_TYPE, REFERENCE_ERROR_TYPE); // SyntaxError FunctionType SYNTAX_ERROR_FUNCTION_TYPE = new ErrorFunctionType(this, "SyntaxError"); SYNTAX_ERROR_FUNCTION_TYPE.setPrototypeBasedOn(ERROR_TYPE); registerNativeType( JSTypeNative.SYNTAX_ERROR_FUNCTION_TYPE, SYNTAX_ERROR_FUNCTION_TYPE); ObjectType SYNTAX_ERROR_TYPE = SYNTAX_ERROR_FUNCTION_TYPE.getInstanceType(); registerNativeType(JSTypeNative.SYNTAX_ERROR_TYPE, SYNTAX_ERROR_TYPE); // TypeError FunctionType TYPE_ERROR_FUNCTION_TYPE = new ErrorFunctionType(this, "TypeError"); TYPE_ERROR_FUNCTION_TYPE.setPrototypeBasedOn(ERROR_TYPE); registerNativeType( JSTypeNative.TYPE_ERROR_FUNCTION_TYPE, TYPE_ERROR_FUNCTION_TYPE); ObjectType TYPE_ERROR_TYPE = TYPE_ERROR_FUNCTION_TYPE.getInstanceType(); registerNativeType(JSTypeNative.TYPE_ERROR_TYPE, TYPE_ERROR_TYPE); // URIError FunctionType URI_ERROR_FUNCTION_TYPE = new ErrorFunctionType(this, "URIError"); URI_ERROR_FUNCTION_TYPE.setPrototypeBasedOn(ERROR_TYPE); registerNativeType( JSTypeNative.URI_ERROR_FUNCTION_TYPE, URI_ERROR_FUNCTION_TYPE); ObjectType URI_ERROR_TYPE = URI_ERROR_FUNCTION_TYPE.getInstanceType(); registerNativeType(JSTypeNative.URI_ERROR_TYPE, URI_ERROR_TYPE); // Number FunctionType NUMBER_OBJECT_FUNCTION_TYPE = new FunctionType(this, "Number", null, createArrowType(createParameters(false, ALL_TYPE), NUMBER_TYPE), null, null, true, true); ObjectType numberPrototype = NUMBER_OBJECT_FUNCTION_TYPE.getPrototype(); registerNativeType( JSTypeNative.NUMBER_OBJECT_FUNCTION

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>_TYPE, NUMBER_OBJECT_FUNCTION_TYPE); ObjectType NUMBER_OBJECT_TYPE = NUMBER_OBJECT_FUNCTION_TYPE.getInstanceType(); registerNativeType(JSTypeNative.NUMBER_OBJECT_TYPE, NUMBER_OBJECT_TYPE); // RegExp FunctionType REGEXP_FUNCTION_TYPE = new FunctionType(this, "RegExp", null, createArrowType(createOptionalParameters(ALL_TYPE, ALL_TYPE)), null, null, true, true); REGEXP_FUNCTION_TYPE.getInternalArrowType().returnType = REGEXP_FUNCTION_TYPE.getInstanceType(); ObjectType regexpPrototype = REGEXP_FUNCTION_TYPE.getPrototype(); registerNativeType(JSTypeNative.REGEXP_FUNCTION_TYPE, REGEXP_FUNCTION_TYPE); ObjectType REGEXP_TYPE = REGEXP_FUNCTION_TYPE.getInstanceType(); registerNativeType(JSTypeNative.REGEXP_TYPE, REGEXP_TYPE); // String FunctionType STRING_OBJECT_FUNCTION_TYPE = new FunctionType(this, "String", null, createArrowType(createParameters(false, ALL_TYPE), STRING_TYPE), null, null, true, true); ObjectType stringPrototype = STRING_OBJECT_FUNCTION_TYPE.getPrototype(); registerNativeType( JSTypeNative.STRING_OBJECT_FUNCTION_TYPE, STRING_OBJECT_FUNCTION_TYPE); ObjectType STRING_OBJECT_TYPE = STRING_OBJECT_FUNCTION_TYPE.getInstanceType(); registerNativeType( JSTypeNative.STRING_OBJECT_TYPE, STRING_OBJECT_TYPE); // (Object,string,number) JSType OBJECT_NUMBER_STRING = createUnionType(OBJECT_TYPE, NUMBER_TYPE, STRING_TYPE); registerNativeType(JSTypeNative.OBJECT_NUMBER_STRING, OBJECT_NUMBER_STRING); // (Object,string,number,boolean) JSType OBJECT_NUMBER_STRING_BOOLEAN = createUnionType(OBJECT_TYPE, NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE); registerNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN, OBJECT_NUMBER_STRING_BOOLEAN); // (string,number,boolean) JSType NUMBER_STRING_BOOLEAN = createUnionType(NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE); registerNativeType(JSTypeNative.NUMBER_STRING_BOOLEAN, NUMBER_STRING_BOOLEAN); // (string,number) JSType NUMBER_STRING = createUnionType(NUMBER_TYPE, STRING_TYPE); registerNativeType(JSTypeNative.NUMBER_STRING, NUMBER_STRING); // Native object properties are filled in by externs... // (String, string) JSType STRING_VALUE_OR_OBJECT_TYPE = createUnionType(STRING_OBJECT_TYPE, STRING_TYPE); registerNativeType( JSTypeNative.STRING_VALUE_OR_OBJECT_TYPE, STRING_VALUE_OR_OBJECT_TYPE); // (Number, number) JSType NUMBER_VALUE_OR_OBJECT_TYPE = createUnionType(NUMBER_OBJECT_TYPE, NUMBER_TYPE); registerNativeType( JSTypeNative.NUMBER_VALUE_OR_OBJECT_TYPE, NUMBER_VALUE_OR_OBJECT_TYPE); // unknown function type, i.e. (?...) -> ? FunctionType U2U_FUNCTION_TYPE = createFunctionType(UNKNOWN_TYPE, true, UNKNOWN_TYPE); registerNativeType(JSTypeNative.U2U_FUNCTION_TYPE, U2U_FUNCTION_TYPE); // unknown constructor type, i.e. (?...) -> ? with the NoObject type // as instance type FunctionType U2U_CONSTRUCTOR_TYPE = // This is equivalent to

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> // createConstructorType(UNKNOWN_TYPE, true, UNKNOWN_TYPE), but, // in addition, overrides getInstanceType() to return the NoObject type // instead of a new anonymous object. new FunctionType(this, "Function", null, createArrowType( createParametersWithVarArgs(UNKNOWN_TYPE), UNKNOWN_TYPE), NO_OBJECT_TYPE, null, true, true) { private static final long serialVersionUID = 1L; @Override public FunctionType getConstructor() { return registry.getNativeFunctionType( JSTypeNative.FUNCTION_FUNCTION_TYPE); } }; // The U2U_CONSTRUCTOR is weird, because it's the supertype of its // own constructor. registerNativeType(JSTypeNative.U2U_CONSTRUCTOR_TYPE, U2U_CONSTRUCTOR_TYPE); registerNativeType( JSTypeNative.FUNCTION_INSTANCE_TYPE, U2U_CONSTRUCTOR_TYPE); FUNCTION_FUNCTION_TYPE.setInstanceType(U2U_CONSTRUCTOR_TYPE); U2U_CONSTRUCTOR_TYPE.setImplicitPrototype(FUNCTION_PROTOTYPE); // least function type, i.e. (All...) -> NoType FunctionType LEAST_FUNCTION_TYPE = createFunctionType(NO_TYPE, true, ALL_TYPE); registerNativeType(JSTypeNative.LEAST_FUNCTION_TYPE, LEAST_FUNCTION_TYPE); // the 'this' object in the global scope ObjectType GLOBAL_THIS = createObjectType("global this", null, UNKNOWN_TYPE /* to be resolved later */); registerNativeType(JSTypeNative.GLOBAL_THIS, GLOBAL_THIS); // greatest function type, i.e. (NoType...) -> All FunctionType GREATEST_FUNCTION_TYPE = createFunctionType(ALL_TYPE, true, NO_TYPE); registerNativeType(JSTypeNative.GREATEST_FUNCTION_TYPE, GREATEST_FUNCTION_TYPE); // Register the prototype property. See the comments below in // registerPropertyOnType about the bootstrapping process. registerPropertyOnType("prototype", OBJECT_FUNCTION_TYPE); } private void initializeRegistry() { register(getNativeType(JSTypeNative.ARRAY_TYPE)); register(getNativeType(JSTypeNative.BOOLEAN_OBJECT_TYPE)); register(getNativeType(JSTypeNative.BOOLEAN_TYPE)); register(getNativeType(JSTypeNative.DATE_TYPE)); register(getNativeType(JSTypeNative.NULL_TYPE)); register(getNativeType(JSTypeNative.NULL_TYPE), "Null"); register(getNativeType(JSTypeNative.NUMBER_OBJECT_TYPE)); register(getNativeType(JSTypeNative.NUMBER_TYPE)); register(getNativeType(JSTypeNative.OBJECT_TYPE)); register(getNativeType(JSTypeNative.ERROR_TYPE)); register(getNativeType(JSTypeNative.URI_ERROR_TYPE)); register(getNativeType(JSTypeNative.EVAL_ERROR_TYPE)); register(getNativeType(JSTypeNative.TYPE_ERROR_TYPE)); register(getNativeType(JSTypeNative.RANGE_ERROR_TYPE)); register(getNativeType(JSTypeNative.REFERENCE_ERROR_TYPE)); register(getNativeType(JSTypeNative.SYNTAX_ERROR_TYPE)); register(getNativeType(JSTypeNative.REGEXP_TYPE)); register(getNativeType(JSTypeNative.STRING_OBJECT_TYPE)); register(getNativeType(JSTypeNative.STRING_TYPE)); register(getNativeType(JSTypeNative.VOID_TYPE)); register(getNativeType(JSType

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>Native.VOID_TYPE), "Undefined"); register(getNativeType(JSTypeNative.VOID_TYPE), "void"); register(getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE), "Function"); } private void register(JSType type) { register(type, type.toString()); } private void register(JSType type, String name) { namesToTypes.put(name, type); // Add all the namespaces in which this name lives. while (name.indexOf('.') > 0) { name = name.substring(0, name.lastIndexOf('.')); namespaces.add(name); } } private void registerNativeType(JSTypeNative typeId, JSType type) { nativeTypes[typeId.ordinal()] = type; } /** * Tells the type system that {@code owner} may have a property named * {@code propertyName}. This allows the registry to keep track of what * types a property is defined upon. * * This is NOT the same as saying that {@code owner} must have a property * named type. ObjectType#hasProperty attempts to minimize false positives * ("if we're not sure, then don't type check this property"). The type * registry, on the other hand, should attempt to minimize false negatives * ("if this property is assigned anywhere in the program, it must * show up in the type registry"). */ public void registerPropertyOnType(String propertyName, JSType type) { UnionTypeBuilder typeSet = typesIndexedByProperty.get(propertyName); if (typeSet == null) { typeSet = new UnionTypeBuilder(this); typesIndexedByProperty.put(propertyName, typeSet); } typeSet.addAlternate(type); addReferenceTypeIndexedByProperty(propertyName, type); // Clear cached values that depend on typesIndexedByProperty. greatestSubtypeByProperty.remove(propertyName); } private void addReferenceTypeIndexedByProperty( String propertyName, JSType type) { if (type instanceof ObjectType && ((ObjectType) type).hasReferenceName()) { Map<String, ObjectType> typeSet = eachRefTypeIndexedByProperty.get(propertyName); if (typeSet == null) { typeSet = Maps.newHashMap(); eachRefTypeIndexedByProperty.put(propertyName, typeSet); } ObjectType objType = (ObjectType) type; typeSet.put(objType.getReferenceName(), objType); } else if (type instanceof NamedType) { addReferenceTypeIndexedByProperty( propertyName, ((NamedType) type).getReferencedType()); } else if (type instanceof UnionType) { for (JSType alternate : ((UnionType) type).getAlternates()) { addReferenceTypeIndexedByProperty(propertyName, alternate); } } } /** * Gets the greatest subtype of the {@code type} that has a property * {@code propertyName} defined on it. */ public JSType getGreatestSubtypeWithProperty( JSType type, String propertyName) { if (greatestSubtypeByProperty.containsKey(propertyName)) { return greatestSubtypeByProperty.get(propertyName) .getGreatestSubtype(type); } if (typesIndexedByProperty.containsKey(propertyName)) { JSType built = typesIndexedByProperty.get(propertyName).build(); greatestSubtypeByProperty.put(propertyName, built); return built.getGreatestSubtype(type); } return getNativeType(NO_TYPE); } /** * Returns whether the given property can possibly be set on the given type. */ public boolean canPropertyBeDefined(JSType type, String propertyName) { if

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>(name)) { return false; } register(t, name); return true; } /** * Overrides a declared global type name. Throws an exception if this * type name hasn't been declared yet. */ public void overwriteDeclaredType(String name, JSType t) { Preconditions.checkState(namesToTypes.containsKey(name)); register(t, name); } /** * Records a forward-declared type name. We will not emit errors if this * type name never resolves to anything. */ public void forwardDeclareType(String name) { forwardDeclaredTypes.add(name); } /** * Whether this is a forward-declared type name. */ public boolean isForwardDeclaredType(String name) { return forwardDeclaredTypes.contains(name); } /** Determines whether the given JS package exists. */ public boolean hasNamespace(String name) { return namespaces.contains(name); } /** * Looks up a type by name. * * @param jsTypeName The name string. * @return the corresponding JSType object or {@code null} it cannot be found */ public JSType getType(String jsTypeName) { // TODO(user): Push every local type name out of namesToTypes so that // NamedType#resolve is correct. if (jsTypeName.equals(templateTypeName)) { return templateType; } return namesToTypes.get(jsTypeName); } public JSType getNativeType(JSTypeNative typeId) { return nativeTypes[typeId.ordinal()]; } public ObjectType getNativeObjectType(JSTypeNative typeId) { return (ObjectType) getNativeType(typeId); } public FunctionType getNativeFunctionType(JSTypeNative typeId) { return (FunctionType) getNativeType(typeId); } /** * Try to resolve a type name, but forgive the user and don't emit * a warning if this doesn't resolve. */ public JSType getForgivingType(StaticScope<JSType> scope, String jsTypeName, String sourceName, int lineno, int charno) { JSType type = getType( scope, jsTypeName, sourceName, lineno, charno); type.forgiveUnknownNames(); return type; } /** * Looks up a type by name. To allow for forward references to types, an * unrecognized string has to be bound to a NamedType object that will be * resolved later. * * @param scope A scope for doing type name resolution. * @param jsTypeName The name string. * @param sourceName The name of the source file where this reference appears. * @param lineno The line number of the reference. * @return a NamedType if the string argument is not one of the known types, * otherwise the corresponding JSType object. */ public JSType getType(StaticScope<JSType> scope, String jsTypeName, String sourceName, int lineno, int charno) { JSType type = getType(jsTypeName); if (type == null) { // TODO(user): Each instance should support named type creation using // interning. NamedType namedType = new NamedType(this, jsTypeName, sourceName, lineno, charno); unresolvedNamedTypes.put(scope, namedType); type = namedType; } return type; } /** * Resolve all the unresolved types in the given scope. */ public void resolveTypesInScope(StaticScope<JSType> scope) { for (NamedType type : unresolvedNamedTypes.get(scope)) { type.resolve(reporter

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>, scope); } resolvedNamedTypes.putAll(scope, unresolvedNamedTypes.removeAll(scope)); if (scope != null && scope.getParentScope() == null) { // By default, the global "this" type is just an anonymous object. // If the user has defined a Window type, make the Window the // implicit prototype of "this". PrototypeObjectType globalThis = (PrototypeObjectType) getNativeType( JSTypeNative.GLOBAL_THIS); JSType windowType = getType("Window"); if (globalThis.isUnknownType()) { ObjectType windowObjType = ObjectType.cast(windowType); if (windowObjType != null) { globalThis.setImplicitPrototype(windowObjType); } else { globalThis.setImplicitPrototype( getNativeObjectType(JSTypeNative.OBJECT_TYPE)); } } } } /** * Creates a type representing optional values of the given type. * @return the union of the type and the void type */ public JSType createOptionalType(JSType type) { if (type instanceof UnknownType || type.isAllType()) { return type; } else { return createUnionType(type, getNativeType(JSTypeNative.VOID_TYPE)); } } /** * Creates a type representing nullable values of the given type. * @return the union of the type and the Null type */ public JSType createDefaultObjectUnion(JSType type) { return shouldTolerateUndefinedValues() ? createOptionalNullableType(type) : createNullableType(type); } /** * Creates a type representing nullable values of the given type. * @return the union of the type and the Null type */ public JSType createNullableType(JSType type) { return createUnionType(type, getNativeType(JSTypeNative.NULL_TYPE)); } /** * Creates a nullabel and undefine-able value of the given type. * @return The union of the type and null and undefined. */ public JSType createOptionalNullableType(JSType type) { return createUnionType(type, getNativeType(JSTypeNative.VOID_TYPE), getNativeType(JSTypeNative.NULL_TYPE)); } /** * Creates a union type whose variants are the arguments. */ public JSType createUnionType(JSType... variants) { UnionTypeBuilder builder = new UnionTypeBuilder(this); for (JSType type : variants) { builder.addAlternate(type); } return builder.build(); } /** * Creates a union type whose variants are the builtin types specified * by the arguments. */ public JSType createUnionType(JSTypeNative... variants) { UnionTypeBuilder builder = new UnionTypeBuilder(this); for (JSTypeNative typeId : variants) { builder.addAlternate(getNativeType(typeId)); } return builder.build(); } /** * Creates an enum type. */ public EnumType createEnumType(String name, JSType elementsType) { return new EnumType(this, name, elementsType); } /** * Creates an arrow type, an abstract representation of the parameters * and return value of a function. * * @param parametersNode the parameters' types, formatted as a Node with * param names and optionality info. * @param returnType the function's return type */ ArrowType createArrowType(Node parametersNode, JSType returnType) { return new ArrowType(this, parametersNode, returnType); } /** * Creates an arrow type with an unknown return type. * *

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>, sourceName, scope, false); if (arg.getType() == Token.EQUALS) { boolean addSuccess = paramBuilder.addOptionalParams(type); if (!addSuccess) { reporter.warning( ScriptRuntime.getMessage0("msg.jsdoc.function.varargs"), sourceName, arg.getLineno(), "", arg.getCharno()); } } else { paramBuilder.addRequiredParams(type); } } } current = current.getNext(); } JSType returnType = createFromTypeNodesInternal(current, sourceName, scope, false); return new FunctionBuilder(this) .withParams(paramBuilder) .withReturnType(returnType) .withTypeOfThis(thisType) .setIsConstructor(isConstructor) .build(); } throw new IllegalStateException( "Unexpected node in type expression: " + n.toString()); } /** * Creates a RecordType from the nodes representing said record type. * @param n The node with type info. * @param sourceName The source file name. * @param scope A scope for doing type name lookups. */ private JSType createRecordTypeFromNodes(Node n, String sourceName, StaticScope<JSType> scope) { RecordTypeBuilder builder = new RecordTypeBuilder(this); // For each of the fields in the record type. for (Node fieldTypeNode = n.getFirstChild(); fieldTypeNode != null; fieldTypeNode = fieldTypeNode.getNext()) { // Get the property's name. Node fieldNameNode = fieldTypeNode; boolean hasType = false; if (fieldTypeNode.getType() == Token.COLON) { fieldNameNode = fieldTypeNode.getFirstChild(); hasType = true; } String fieldName = fieldNameNode.getString(); // TODO(user): Move this into the lexer/parser. // Remove the string literal characters around a field name, // if any. if (fieldName.startsWith("'") || fieldName.startsWith("\"")) { fieldName = fieldName.substring(1, fieldName.length() - 1); } // Get the property's type. JSType fieldType = null; if (hasType) { // We have a declared type. fieldType = createFromTypeNodesInternal( fieldTypeNode.getLastChild(), sourceName, scope, false); } else { // Otherwise, the type is UNKNOWN. fieldType = getNativeType(JSTypeNative.UNKNOWN_TYPE); } // Add the property to the record. builder.addProperty(fieldName, fieldType, fieldNameNode); } return builder.build(); } /** * Sets the template type name. */ public void setTemplateTypeName(String name) { templateTypeName = name; templateType = new TemplateType(this, name); } /** * Clears the template type name. */ public void clearTemplateTypeName() { templateTypeName = null; templateType = null; } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import static com.google.javascript.rhino.jstype.JSTypeNative.UNKNOWN_TYPE; import com.google.javascript.rhino.ErrorReporter; import com.google.javascript.rhino.Node; /** * The arrow type is an internal type that models the functional arrow type * seen in typical functional programming languages. It is used soley for * separating the management of the arrow type from the complex * {@link FunctionType} that models JavaScript's notion of functions. */ final class ArrowType extends JSType { private static final long serialVersionUID = 1L; final Node parameters; JSType returnType; // Whether the return type is inferred. final boolean returnTypeInferred; ArrowType(JSTypeRegistry registry, Node parameters, JSType returnType) { this(registry, parameters, returnType, false); } ArrowType(JSTypeRegistry registry, Node parameters, JSType returnType, boolean returnTypeInferred) { super(registry); this.parameters = parameters == null ? registry.createParametersWithVarArgs(getNativeType(UNKNOWN_TYPE)) : parameters; this.returnType = returnType == null ? getNativeType(UNKNOWN_TYPE) : returnType; this.returnTypeInferred = returnTypeInferred; } @Override public boolean isSubtype(JSType other) { if (!(other instanceof ArrowType)) { return false; } ArrowType that = (ArrowType) other; // this.returnType <: that.returnType (covariant) if (!this.returnType.isSubtype(that.returnType)) { return false; } // that.paramType[i] <: this.paramType[i] (contravariant) // TODO(nicksantos): This is incorrect. It should be

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.testing; import com.google.javascript.rhino.JSTypeExpression; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.jstype.FunctionBuilder; import com.google.javascript.rhino.jstype.FunctionType; import com.google.javascript.rhino.jstype.JSType; import com.google.javascript.rhino.jstype.JSTypeNative; import com.google.javascript.rhino.jstype.JSTypeRegistry; import com.google.javascript.rhino.jstype.ObjectType; import com.google.javascript.rhino.jstype.RecordTypeBuilder; import junit.framework.TestCase; public abstract class BaseJSTypeTestCase extends TestCase { protected JSTypeRegistry registry; protected TestErrorReporter errorReporter; protected JSType ALL_TYPE; protected ObjectType NO_OBJECT_TYPE; protected ObjectType NO_TYPE; protected ObjectType NO_RESOLVED_TYPE; protected JSType ARRAY_FUNCTION_TYPE; protected ObjectType ARRAY_TYPE; protected JSType BOOLEAN_OBJECT_FUNCTION_TYPE; protected ObjectType BOOLEAN_OBJECT_TYPE; protected JSType BOOLEAN_TYPE; protected JSType CHECKED_UNKNOWN_TYPE; protected JSType DATE_FUNCTION_TYPE; protected ObjectType DATE_TYPE; protected JSType ERROR_FUNCTION_TYPE; protected ObjectType ERROR_TYPE; protected JSType EVAL_ERROR_FUNCTION_TYPE; protected ObjectType EVAL_ERROR_TYPE; protected FunctionType FUNCTION_FUNCTION_TYPE; protected FunctionType FUNCTION_INSTANCE_TYPE; protected ObjectType FUNCTION_PROTOTYPE; protected JSType GREATEST_FUNCTION_TYPE; protected JSType LEAST_FUNCTION_TYPE; protected JSType MATH_TYPE; protected JSType NULL

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>_TYPE; protected JSType NUMBER_OBJECT_FUNCTION_TYPE; protected ObjectType NUMBER_OBJECT_TYPE; protected JSType NUMBER_STRING_BOOLEAN; protected JSType NUMBER_TYPE; protected FunctionType OBJECT_FUNCTION_TYPE; protected JSType OBJECT_NUMBER_STRING; protected JSType OBJECT_NUMBER_STRING_BOOLEAN; protected JSType OBJECT_PROTOTYPE; protected ObjectType OBJECT_TYPE; protected JSType RANGE_ERROR_FUNCTION_TYPE; protected ObjectType RANGE_ERROR_TYPE; protected JSType REFERENCE_ERROR_FUNCTION_TYPE; protected ObjectType REFERENCE_ERROR_TYPE; protected JSType REGEXP_FUNCTION_TYPE; protected ObjectType REGEXP_TYPE; protected JSType STRING_OBJECT_FUNCTION_TYPE; protected ObjectType STRING_OBJECT_TYPE; protected JSType STRING_TYPE; protected JSType SYNTAX_ERROR_FUNCTION_TYPE; protected ObjectType SYNTAX_ERROR_TYPE; protected JSType TYPE_ERROR_FUNCTION_TYPE; protected ObjectType TYPE_ERROR_TYPE; protected FunctionType U2U_CONSTRUCTOR_TYPE; protected FunctionType U2U_FUNCTION_TYPE; protected ObjectType UNKNOWN_TYPE; protected JSType URI_ERROR_FUNCTION_TYPE; protected ObjectType URI_ERROR_TYPE; protected JSType VOID_TYPE; protected int NATIVE_PROPERTIES_COUNT; @Override protected void setUp() throws Exception { super.setUp(); errorReporter = new TestErrorReporter(null, null); registry = new JSTypeRegistry(errorReporter); initTypes(); } protected void initTypes() { ALL_TYPE = registry.getNativeType(JSTypeNative.ALL_TYPE); NO_OBJECT_TYPE = registry.getNativeObjectType(JSTypeNative.NO_OBJECT_TYPE); NO_TYPE = registry.getNativeObjectType(JSTypeNative.NO_TYPE); NO_RESOLVED_TYPE = registry.getNativeObjectType(JSTypeNative.NO_RESOLVED_TYPE); ARRAY_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.ARRAY_FUNCTION_TYPE); ARRAY_TYPE = registry.getNativeObjectType(JSTypeNative.ARRAY_TYPE); BOOLEAN_OBJECT_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.BOOLEAN_OBJECT_FUNCTION_TYPE); BOOLEAN_OBJECT_TYPE = registry.getNativeObjectType(JSTypeNative.BOOLEAN_OBJECT_TYPE); BOOLEAN_TYPE = registry.getNativeType(JSTypeNative.BOOLEAN_TYPE); CHECKED_UNKNOWN_TYPE = registry.getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE); DATE_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.DATE_FUNCTION_TYPE); DATE_TYPE = registry.getNativeObjectType(JSTypeNative.DATE_TYPE); ERROR_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.ERROR_FUNCTION_TYPE); ERROR_TYPE = registry.getNativeObjectType(JSTypeNative.ERROR_TYPE); EVAL_ERROR_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.EVAL_ERROR_FUNCTION_TYPE); EVAL_ERROR_TYPE = registry.getNativeObjectType(JSTypeNative.EVAL_ERROR_TYPE); FUNCTION_FUNCTION_TYPE = registry.getNativeFunctionType(JSTypeNative.FUNCTION_FUNCTION_TYPE); FUNCTION_INSTANCE_TYPE = registry.getNativeFunctionType(JSTypeNative.FUNCTION_INSTANCE_TYPE); FUNCTION_PROTOTYPE = registry.getNativeObjectType(JSTypeNative.FUNCTION_PROTOTYPE); GREATEST_FUNCTION_TYPE = registry.getNative

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>Type(JSTypeNative.GREATEST_FUNCTION_TYPE); LEAST_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.LEAST_FUNCTION_TYPE); NULL_TYPE = registry.getNativeType(JSTypeNative.NULL_TYPE); NUMBER_OBJECT_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.NUMBER_OBJECT_FUNCTION_TYPE); NUMBER_OBJECT_TYPE = registry.getNativeObjectType(JSTypeNative.NUMBER_OBJECT_TYPE); NUMBER_STRING_BOOLEAN = registry.getNativeType(JSTypeNative.NUMBER_STRING_BOOLEAN); NUMBER_TYPE = registry.getNativeType(JSTypeNative.NUMBER_TYPE); OBJECT_FUNCTION_TYPE = registry.getNativeFunctionType(JSTypeNative.OBJECT_FUNCTION_TYPE); OBJECT_NUMBER_STRING = registry.getNativeType(JSTypeNative.OBJECT_NUMBER_STRING); OBJECT_NUMBER_STRING_BOOLEAN = registry.getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN); OBJECT_PROTOTYPE = registry.getNativeType(JSTypeNative.OBJECT_PROTOTYPE); OBJECT_TYPE = registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE); RANGE_ERROR_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.RANGE_ERROR_FUNCTION_TYPE); RANGE_ERROR_TYPE = registry.getNativeObjectType(JSTypeNative.RANGE_ERROR_TYPE); REFERENCE_ERROR_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.REFERENCE_ERROR_FUNCTION_TYPE); REFERENCE_ERROR_TYPE = registry.getNativeObjectType(JSTypeNative.REFERENCE_ERROR_TYPE); REGEXP_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.REGEXP_FUNCTION_TYPE); REGEXP_TYPE = registry.getNativeObjectType(JSTypeNative.REGEXP_TYPE); STRING_OBJECT_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.STRING_OBJECT_FUNCTION_TYPE); STRING_OBJECT_TYPE = registry.getNativeObjectType(JSTypeNative.STRING_OBJECT_TYPE); STRING_TYPE = registry.getNativeType(JSTypeNative.STRING_TYPE); SYNTAX_ERROR_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.SYNTAX_ERROR_FUNCTION_TYPE); SYNTAX_ERROR_TYPE = registry.getNativeObjectType(JSTypeNative.SYNTAX_ERROR_TYPE); TYPE_ERROR_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.TYPE_ERROR_FUNCTION_TYPE); TYPE_ERROR_TYPE = registry.getNativeObjectType(JSTypeNative.TYPE_ERROR_TYPE); U2U_CONSTRUCTOR_TYPE = registry.getNativeFunctionType(JSTypeNative.U2U_CONSTRUCTOR_TYPE); U2U_FUNCTION_TYPE = registry.getNativeFunctionType(JSTypeNative.U2U_FUNCTION_TYPE); UNKNOWN_TYPE = registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE); URI_ERROR_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.URI_ERROR_FUNCTION_TYPE); URI_ERROR_TYPE = registry.getNativeObjectType(JSTypeNative.URI_ERROR_TYPE); VOID_TYPE = registry.getNativeType(JSTypeNative.VOID_TYPE); addNativeProperties(registry); NATIVE_PROPERTIES_COUNT = OBJECT_TYPE.getPropertiesCount(); } /** Adds a basic set of properties to the native types. */ public static void addNativeProperties(JSTypeRegistry registry) {

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> JSType booleanType = registry.getNativeType(JSTypeNative.BOOLEAN_TYPE); JSType numberType = registry.getNativeType(JSTypeNative.NUMBER_TYPE); JSType stringType = registry.getNativeType(JSTypeNative.STRING_TYPE); JSType unknownType = registry.getNativeType(JSTypeNative.UNKNOWN_TYPE); ObjectType objectType = registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE); ObjectType arrayType = registry.getNativeObjectType(JSTypeNative.ARRAY_TYPE); ObjectType dateType = registry.getNativeObjectType(JSTypeNative.DATE_TYPE); ObjectType regexpType = registry.getNativeObjectType(JSTypeNative.REGEXP_TYPE); ObjectType booleanObjectType = registry.getNativeObjectType(JSTypeNative.BOOLEAN_OBJECT_TYPE); ObjectType numberObjectType = registry.getNativeObjectType(JSTypeNative.NUMBER_OBJECT_TYPE); ObjectType stringObjectType = registry.getNativeObjectType(JSTypeNative.STRING_OBJECT_TYPE); ObjectType objectPrototype = registry .getNativeFunctionType(JSTypeNative.OBJECT_FUNCTION_TYPE) .getPrototype(); addMethod(registry, objectPrototype, "constructor", objectType); addMethod(registry, objectPrototype, "toString", stringType); addMethod(registry, objectPrototype, "toLocaleString", stringType); addMethod(registry, objectPrototype, "valueOf", unknownType); addMethod(registry, objectPrototype, "hasOwnProperty", booleanType); addMethod(registry, objectPrototype, "isPrototypeOf", booleanType); addMethod(registry, objectPrototype, "propertyIsEnumerable", booleanType); ObjectType arrayPrototype = registry .getNativeFunctionType(JSTypeNative.ARRAY_FUNCTION_TYPE) .getPrototype(); addMethod(registry, arrayPrototype, "constructor", arrayType); addMethod(registry, arrayPrototype, "toString", stringType); addMethod(registry, arrayPrototype, "toLocaleString", stringType); addMethod(registry, arrayPrototype, "concat", arrayType); addMethod(registry, arrayPrototype, "join", stringType); addMethod(registry, arrayPrototype, "pop", unknownType); addMethod(registry, arrayPrototype, "push", numberType); addMethod(registry, arrayPrototype, "reverse", arrayType); addMethod(registry, arrayPrototype, "shift", unknownType); addMethod(registry, arrayPrototype, "slice", arrayType); addMethod(registry, arrayPrototype, "sort", arrayType); addMethod(registry, arrayPrototype, "splice", arrayType); addMethod(registry, arrayPrototype, "unshift", numberType); arrayType.defineDeclaredProperty("length", numberType, true, null); ObjectType booleanPrototype = registry .getNativeFunctionType(JSTypeNative.BOOLEAN_OBJECT_FUNCTION_TYPE) .getPrototype(); addMethod(registry, booleanPrototype, "constructor", booleanObjectType); addMethod(registry, booleanPrototype, "toString", stringType); addMethod(registry, booleanPrototype, "valueOf", booleanType); ObjectType datePrototype = registry .getNativeFunctionType(JSTypeNative.DATE_FUNCTION_TYPE) .getPrototype(); addMethod(registry, datePrototype, "constructor", dateType); addMethod(registry, datePrototype, "toString", stringType); addMethod(registry, datePrototype, "toDateString", stringType); addMethod(registry, datePrototype, "toTimeString", stringType); addMethod(registry, datePrototype, "toLocaleString", stringType); addMethod(registry, datePrototype, "toLocaleDateString", stringType); addMethod(registry, datePrototype, "toLocaleTimeString", string

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>Type); addMethod(registry, datePrototype, "valueOf", numberType); addMethod(registry, datePrototype, "getTime", numberType); addMethod(registry, datePrototype, "getFullYear", numberType); addMethod(registry, datePrototype, "getUTCFullYear", numberType); addMethod(registry, datePrototype, "getMonth", numberType); addMethod(registry, datePrototype, "getUTCMonth", numberType); addMethod(registry, datePrototype, "getDate", numberType); addMethod(registry, datePrototype, "getUTCDate", numberType); addMethod(registry, datePrototype, "getDay", numberType); addMethod(registry, datePrototype, "getUTCDay", numberType); addMethod(registry, datePrototype, "getHours", numberType); addMethod(registry, datePrototype, "getUTCHours", numberType); addMethod(registry, datePrototype, "getMinutes", numberType); addMethod(registry, datePrototype, "getUTCMinutes", numberType); addMethod(registry, datePrototype, "getSeconds", numberType); addMethod(registry, datePrototype, "getUTCSeconds", numberType); addMethod(registry, datePrototype, "getMilliseconds", numberType); addMethod(registry, datePrototype, "getUTCMilliseconds", numberType); addMethod(registry, datePrototype, "getTimezoneOffset", numberType); addMethod(registry, datePrototype, "setTime", numberType); addMethod(registry, datePrototype, "setMilliseconds", numberType); addMethod(registry, datePrototype, "setUTCMilliseconds", numberType); addMethod(registry, datePrototype, "setSeconds", numberType); addMethod(registry, datePrototype, "setUTCSeconds", numberType); addMethod(registry, datePrototype, "setMinutes", numberType); addMethod(registry, datePrototype, "setUTCMinutes", numberType); addMethod(registry, datePrototype, "setHours", numberType); addMethod(registry, datePrototype, "setUTCHours", numberType); addMethod(registry, datePrototype, "setDate", numberType); addMethod(registry, datePrototype, "setUTCDate", numberType); addMethod(registry, datePrototype, "setMonth", numberType); addMethod(registry, datePrototype, "setUTCMonth", numberType); addMethod(registry, datePrototype, "setFullYear", numberType); addMethod(registry, datePrototype, "setUTCFullYear", numberType); addMethod(registry, datePrototype, "toUTCString", stringType); addMethod(registry, datePrototype, "toGMTString", stringType); ObjectType numberPrototype = registry .getNativeFunctionType(JSTypeNative.NUMBER_OBJECT_FUNCTION_TYPE) .getPrototype(); addMethod(registry, numberPrototype, "constructor", numberObjectType); addMethod(registry, numberPrototype, "toString", stringType); addMethod(registry, numberPrototype, "toLocaleString", stringType); addMethod(registry, numberPrototype, "valueOf", numberType); addMethod(registry, numberPrototype, "toFixed", stringType); addMethod(registry, numberPrototype, "toExponential", stringType); addMethod(registry, numberPrototype, "toPrecision", stringType); ObjectType regexpPrototype = registry .getNativeFunctionType(JSTypeNative.REGEXP_FUNCTION_TYPE) .getPrototype(); addMethod(registry, regexpPrototype, "constructor", regexpType); addMethod(registry, regexpPrototype, "exec", registry.createNullableType(arrayType)); addMethod(registry, regexpPrototype, "test

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>", booleanType); addMethod(registry, regexpPrototype, "toString", stringType); regexpType.defineDeclaredProperty("source", stringType, true, null); regexpType.defineDeclaredProperty("global", booleanType, true, null); regexpType.defineDeclaredProperty("ignoreCase", booleanType, true, null); regexpType.defineDeclaredProperty("multiline", booleanType, true, null); regexpType.defineDeclaredProperty("lastIndex", numberType, true, null); ObjectType stringPrototype = registry .getNativeFunctionType(JSTypeNative.STRING_OBJECT_FUNCTION_TYPE) .getPrototype(); addMethod(registry, stringPrototype, "constructor", stringObjectType); addMethod(registry, stringPrototype, "toString", stringType); addMethod(registry, stringPrototype, "valueOf", stringType); addMethod(registry, stringPrototype, "charAt", stringType); addMethod(registry, stringPrototype, "charCodeAt", numberType); addMethod(registry, stringPrototype, "concat", stringType); addMethod(registry, stringPrototype, "indexOf", numberType); addMethod(registry, stringPrototype, "lastIndexOf", numberType); addMethod(registry, stringPrototype, "localeCompare", numberType); addMethod(registry, stringPrototype, "match", registry.createNullableType(arrayType)); addMethod(registry, stringPrototype, "replace", stringType); addMethod(registry, stringPrototype, "search", numberType); addMethod(registry, stringPrototype, "slice", stringType); addMethod(registry, stringPrototype, "split", arrayType); addMethod(registry, stringPrototype, "substring", stringType); addMethod(registry, stringPrototype, "toLowerCase", stringType); addMethod(registry, stringPrototype, "toLocaleLowerCase", stringType); addMethod(registry, stringPrototype, "toUpperCase", stringType); addMethod(registry, stringPrototype, "toLocaleUpperCase", stringType); stringObjectType.defineDeclaredProperty("length", numberType, true, null); } private static void addMethod( JSTypeRegistry registry, ObjectType receivingType, String methodName, JSType returnType) { receivingType.defineDeclaredProperty(methodName, new FunctionBuilder(registry).withReturnType(returnType).build(), true, null); } protected JSType createUnionType(JSType... variants) { return registry.createUnionType(variants); } protected RecordTypeBuilder createRecordTypeBuilder() { return new RecordTypeBuilder(registry); } protected JSType createNullableType(JSType type) { return registry.createNullableType(type); } protected JSType createOptionalType(JSType type) { return registry.createOptionalType(type); } /** * Asserts that a Node representing a type expression resolves to the * correct {@code JSType}. */ protected void assertTypeEquals(JSType expected, Node actual) { assertTypeEquals(expected, new JSTypeExpression(actual, "")); } /** * Asserts that a a type expression resolves to the correct {@code JSType}. */ protected void assertTypeEquals(JSType expected, JSTypeExpression actual) { assertEquals(expected, resolve(actual)); } /** * Resolves a type expression, expecting the given warnings. */ protected JSType resolve(JSTypeExpression n, String... warnings) { errorReporter.setWarnings(warnings); return n.evaluate(null, registry); } /** * A definition of all extern types. This should be kept in sync with * javascript/externs/es3.js. This is used to check that the builtin types * declared in {@link JSTypeRegistry

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>/* * Copyright 2008 The Closure Compiler Authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.javascript.jscomp.CompilerOptions.LanguageMode; import com.google.javascript.rhino.testing.BaseJSTypeTestCase; abstract class CompilerTypeTestCase extends BaseJSTypeTestCase { static final String ACTIVE_X_OBJECT_DEF = "/**\n" + " * @param {string} progId\n" + " * @param {string=} opt_location\n" + " * @constructor\n" + " * @see http://msdn.microsoft.com/en-us/library/7sw4ddf8.aspx\n" + " */\n" + "function ActiveXObject(progId, opt_location) {}\n"; static final String CLOSURE_DEFS = "var goog = {};" + "goog.inherits = function(x, y) {};" + "goog.abstractMethod = function() {};" + "goog.isArray = function(x) {};" + "goog.isDef = function(x) {};" + "goog.isFunction = function(x) {};" + "goog.isNull = function(x) {};" + "goog.isString = function(x) {};" + "goog.isObject = function(x) {};" + "goog.isDefAndNotNull = function(x) {};"; /** A default set of externs for testing. */ static final String DEFAULT_EXTERNS = "/** @constructor \n * @param {*} var_args */ " + "function Function(var_args) {}" + "/** @type {!Function} */ Function.prototype.apply;" + "/** @type {!Function} */ Function.prototype.call;" + "/** @constructor \n * @param {*} arg \n @return {string} */" + "function String(arg) {}" + "/** @type {number} */ String.prototype.length;" + "/** @constructor \n * @param {*} var_args \n @return {!Array} */" + "function Array(var_args) {}" + "/** @type {number} */ Array.prototype.length;" + ACTIVE_X_OBJECT_DEF; protected Compiler compiler; protected CompilerOptions getOptions() { CompilerOptions options = new CompilerOptions(); options.languageIn = LanguageMode.ECMASCRIPT5; options.setWarningLevel( DiagnosticGroups.MISSING_PROPERTIES, CheckLevel.WARNING); options.setCodingConvention(getCodingConvention()); return options; } protected CodingConvention getCodingConvention() { return new GoogleCodingConvention(); } @Override protected void setUp() throws Exception { compiler = new Compiler(); compiler.initOptions(getOptions()); registry = compiler.getTypeRegistry(); initTypes(); } }

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> */ @VisibleForTesting Scope createInitialScope(Node root) { NodeTraversal.traverse( compiler, root, new DiscoverEnumsAndTypedefs(typeRegistry)); Scope s = new Scope(root, compiler); declareNativeFunctionType(s, ARRAY_FUNCTION_TYPE); declareNativeFunctionType(s, BOOLEAN_OBJECT_FUNCTION_TYPE); declareNativeFunctionType(s, DATE_FUNCTION_TYPE); declareNativeFunctionType(s, ERROR_FUNCTION_TYPE); declareNativeFunctionType(s, EVAL_ERROR_FUNCTION_TYPE); declareNativeFunctionType(s, FUNCTION_FUNCTION_TYPE); declareNativeFunctionType(s, NUMBER_OBJECT_FUNCTION_TYPE); declareNativeFunctionType(s, OBJECT_FUNCTION_TYPE); declareNativeFunctionType(s, RANGE_ERROR_FUNCTION_TYPE); declareNativeFunctionType(s, REFERENCE_ERROR_FUNCTION_TYPE); declareNativeFunctionType(s, REGEXP_FUNCTION_TYPE); declareNativeFunctionType(s, STRING_OBJECT_FUNCTION_TYPE); declareNativeFunctionType(s, SYNTAX_ERROR_FUNCTION_TYPE); declareNativeFunctionType(s, TYPE_ERROR_FUNCTION_TYPE); declareNativeFunctionType(s, URI_ERROR_FUNCTION_TYPE); declareNativeValueType(s, "undefined", VOID_TYPE); // The typedef construct needs the any type, so that it can be assigned // to anything. This is kind of a hack, and an artifact of the typedef // syntax we've chosen. declareNativeValueType(s, LEGACY_TYPEDEF, NO_TYPE); // ActiveXObject is unqiuely special, because it can be used to construct // any type (the type that it creates is related to the arguments you // pass to it). declareNativeValueType(s, "ActiveXObject", NO_OBJECT_TYPE); return s; } private void declareNativeFunctionType(Scope scope, JSTypeNative tId) { FunctionType t = typeRegistry.getNativeFunctionType(tId); declareNativeType(scope, t.getInstanceType().getReferenceName(), t); declareNativeType( scope, t.getPrototype().getReferenceName(), t.getPrototype()); } private void declareNativeValueType(Scope scope, String name, JSTypeNative tId) { declareNativeType(scope, name, typeRegistry.getNativeType(tId)); } private void declareNativeType(Scope scope, String name, JSType t) { scope.declare(name, null, t, null, false); } private static class DiscoverEnumsAndTypedefs extends AbstractShallowStatementCallback { private final JSTypeRegistry registry; DiscoverEnumsAndTypedefs(JSTypeRegistry registry) { this.registry = registry; } @Override public void visit(NodeTraversal t, Node node, Node parent) { Node nameNode = null; switch (node.getType()) { case Token.VAR: for (Node child = node.getFirstChild(); child != null; child = child.getNext()) { identifyNameNode( child, child.getFirstChild(), NodeUtil.getInfoForNameNode(child)); } break; case Token.EXPR_RESULT: Node firstChild = node.getFirstChild(); if (firstChild.getType() == Token.ASSIGN) { identifyNameNode( firstChild.getFirstChild(), firstChild.getLastChild(), firstChild.getJSDocInfo()); } else { identifyNameNode( firstChild, null, firstChild.getJSDocInfo()); } break; } } private void identifyNameNode( Node nameNode, Node valueNode, JSDocInfo info) { if (nameNode

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>.isQualifiedName()) { if (info != null) { if (info.hasEnumParameterType()) { registry.identifyNonNullableName(nameNode.getQualifiedName()); } else if (info.hasTypedefType()) { registry.identifyNonNullableName(nameNode.getQualifiedName()); } } if (valueNode != null && LEGACY_TYPEDEF.equals(valueNode.getQualifiedName())) { registry.identifyNonNullableName(nameNode.getQualifiedName()); } } } } /** * Given a node, determines whether that node names a prototype * property, and if so, returns the qualified name node representing * the owner of that property. Otherwise, returns null. */ private static Node getPrototypePropertyOwner(Node n) { if (n.getType() == Token.GETPROP) { Node firstChild = n.getFirstChild(); if (firstChild.getType() == Token.GETPROP && firstChild.getLastChild().getString().equals("prototype")) { Node maybeOwner = firstChild.getFirstChild(); if (maybeOwner.isQualifiedName()) { return maybeOwner; } } } return null; } private JSType getNativeType(JSTypeNative nativeType) { return typeRegistry.getNativeType(nativeType); } private abstract class AbstractScopeBuilder implements NodeTraversal.Callback { /** * The scope that we're builidng. */ final Scope scope; private final List<DeferredSetType> deferredSetTypes = Lists.newArrayList(); /** * Functions that we found in the global scope and not in externs. */ private final List<Node> nonExternFunctions = Lists.newArrayList(); /** * Type-less stubs. * * If at the end of traversal, we still don't have types for these * stubs, then we should declare UNKNOWN types. */ private final List<StubDeclaration> stubDeclarations = Lists.newArrayList(); /** * The current source file that we're in. */ private String sourceName = null; private AbstractScopeBuilder(Scope scope) { this.scope = scope; } void setDeferredType(Node node, JSType type) { deferredSetTypes.add(new DeferredSetType(node, type)); } void resolveTypes() { // Resolve types and attach them to nodes. for (DeferredSetType deferred : deferredSetTypes) { deferred.resolve(scope); } // Resolve types and attach them to scope slots. Iterator<Var> vars = scope.getVars(); while (vars.hasNext()) { vars.next().resolveType(typeParsingErrorReporter); } // Tell the type registry that any remaining types // are unknown. typeRegistry.resolveTypesInScope(scope); } @Override public final boolean shouldTraverse(NodeTraversal nodeTraversal, Node n, Node parent) { if (n.getType() == Token.FUNCTION || n.getType() == Token.SCRIPT) { sourceName = (String) n.getProp(Node.SOURCENAME_PROP); } // We do want to traverse the name of a named function, but we don't // want to traverse the arguments or body. return parent == null || parent.getType() != Token.FUNCTION || n == parent.getFirstChild() || parent == scope.getRootNode(); } @Override public void visit(NodeTraversal t, Node n, Node parent) { attachLiteralTypes(t, n); switch (n.getType()) { case Token.CALL: checkForClassDefiningCalls(t, n, parent); break;

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> // who declare "global" names in an anonymous namespace. Scope scopeToDeclareIn = scope; if (n.getType() == Token.GETPROP && !scope.isGlobal() && isQnameRootedInGlobalScope(n)) { Scope globalScope = scope.getGlobalScope(); // don't try to declare in the global scope if there's // already a symbol there with this name. if (!globalScope.isDeclared(variableName, false)) { scopeToDeclareIn = scope.getGlobalScope(); } } // declared in closest scope? if (scopeToDeclareIn.isDeclared(variableName, false)) { Var oldVar = scopeToDeclareIn.getVar(variableName); validator.expectUndeclaredVariable( sourceName, n, parent, oldVar, variableName, type); } else { if (!inferred) { setDeferredType(n, type); } CompilerInput input = compiler.getInput(sourceName); boolean isExtern = input.isExtern(); Var newVar = scopeToDeclareIn.declare(variableName, n, type, input, inferred); if (shouldDeclareOnGlobalThis) { ObjectType globalThis = typeRegistry.getNativeObjectType(JSTypeNative.GLOBAL_THIS); if (inferred) { globalThis.defineInferredProperty(variableName, type == null ? getNativeType(JSTypeNative.NO_TYPE) : type, isExtern, n); } else { globalThis.defineDeclaredProperty(variableName, type, isExtern, n); } } if (type instanceof EnumType) { Node initialValue = newVar.getInitialValue(); boolean isValidValue = initialValue != null && (initialValue.getType() == Token.OBJECTLIT || initialValue.isQualifiedName()); if (!isValidValue) { compiler.report(JSError.make(sourceName, n, ENUM_INITIALIZER)); } } // We need to do some additional work for constructors and interfaces. if (type instanceof FunctionType && // We don't want to look at empty function types. !type.isEmptyType()) { FunctionType fnType = (FunctionType) type; if ((fnType.isConstructor() || fnType.isInterface()) && !fnType.equals(getNativeType(U2U_CONSTRUCTOR_TYPE))) { // Declare var.prototype in the scope chain. FunctionType superClassCtor = fnType.getSuperClassConstructor(); scopeToDeclareIn.declare(variableName + ".prototype", n, fnType.getPrototype(), input, /* declared iff there's an explicit supertype */ superClassCtor == null || superClassCtor.getInstanceType().equals( getNativeType(OBJECT_TYPE))); // Make sure the variable is initialized to something if // it constructs itself. if (newVar.getInitialValue() == null && !isExtern && // We want to make sure that when we declare a new instance // type (with @constructor) that there's actually a ctor for it. // This doesn't apply to structural constructors // (like function(new:Array). Checking the constructed // type against the variable name is a sufficient check for // this. variableName.equals( fnType.getInstanceType().getReferenceName())) { compiler.report( JSError.make(sourceName, n, fnType.isConstructor() ? CTOR_INITIALIZER : IFACE_INITIALIZER, variableName)); } } } } } /** * Check if the given node is a property of a name in the global scope. */ private

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS>. */ private final Kind kind; /** * The type of {@code this} in the scope of this function. */ private ObjectType typeOfThis; /** * The function node which this type represents. It may be {@code null}. */ private Node source; /** * The interfaces directly implemented by this function. * It is only relevant for constructors. May not be {@code null}. */ private List<ObjectType> implementedInterfaces = ImmutableList.of(); /** * The types which are subtypes of this function. It is only relevant for * constructors and may be {@code null}. */ private List<FunctionType> subTypes; /** * The template type name. May be {@code null}. */ private String templateTypeName; /** Creates an instance for a function that might be a constructor. */ FunctionType(JSTypeRegistry registry, String name, Node source, ArrowType arrowType, ObjectType typeOfThis, String templateTypeName, boolean isConstructor, boolean nativeType) { super(registry, name, registry.getNativeObjectType(JSTypeNative.FUNCTION_INSTANCE_TYPE), nativeType); Preconditions.checkArgument(source == null || Token.FUNCTION == source.getType()); Preconditions.checkNotNull(arrowType); this.source = source; this.kind = isConstructor ? Kind.CONSTRUCTOR : Kind.ORDINARY; if (isConstructor) { this.typeOfThis = typeOfThis != null ? typeOfThis : new InstanceObjectType(registry, this, nativeType); } else { this.typeOfThis = typeOfThis != null ? typeOfThis : registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE); } this.call = arrowType; this.templateTypeName = templateTypeName; } /** Creates an instance for a function that is an interface. */ private FunctionType(JSTypeRegistry registry, String name, Node source) { super(registry, name, registry.getNativeObjectType(JSTypeNative.FUNCTION_INSTANCE_TYPE)); Preconditions.checkArgument(source == null || Token.FUNCTION == source.getType()); Preconditions.checkArgument(name != null); this.source = source; this.call = new ArrowType(registry, new Node(Token.LP), null); this.kind = Kind.INTERFACE; this.typeOfThis = new InstanceObjectType(registry, this); } /** Creates an instance for a function that is an interface. */ static FunctionType forInterface( JSTypeRegistry registry, String name, Node source) { return new FunctionType(registry, name, source); } @Override public boolean isInstanceType() { // The universal constructor is its own instance, bizarrely. return isEquivalentTo(registry.getNativeType(U2U_CONSTRUCTOR_TYPE)); } @Override public boolean isConstructor() { return kind == Kind.CONSTRUCTOR; } @Override public boolean isInterface() { return kind == Kind.INTERFACE; } @Override public boolean isOrdinaryFunction() { return kind == Kind.ORDINARY; } @Override public boolean isFunctionType() { return true; } @Override public boolean canBeCalled() { return true; } public Iterable<Node> getParameters() { Node n = getParametersNode(); if (n != null) { return n.children(); } else { return Collections.emptySet(); } } /** Gets an LP node that contains all params. May be null. */ public Node getParametersNode() { return call.parameters; } /** Gets the minimum number of arguments that this

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> function requires. */ public int getMinArguments() { // NOTE(nicksantos): There are some native functions that have optional // parameters before required parameters. This algorithm finds the position // of the last required parameter. int i = 0; int min = 0; for (Node n : getParameters()) { i++; if (!n.isOptionalArg() && !n.isVarArgs()) { min = i; } } return min; } /** * Gets the maximum number of arguments that this function requires, * or Integer.MAX_VALUE if this is a variable argument function. */ public int getMaxArguments() { Node params = getParametersNode(); if (params != null) { Node lastParam = params.getLastChild(); if (lastParam == null || !lastParam.isVarArgs()) { return params.getChildCount(); } } return Integer.MAX_VALUE; } public JSType getReturnType() { return call.returnType; } public boolean isReturnTypeInferred() { return call.returnTypeInferred; } /** Gets the internal arrow type. For use by subclasses only. */ ArrowType getInternalArrowType() { return call; } /** * Gets the {@code prototype} property of this function type. This is * equivalent to {@code (ObjectType) getPropertyType("prototype")}. */ public FunctionPrototypeType getPrototype() { // lazy initialization of the prototype field if (prototype == null) { setPrototype(new FunctionPrototypeType(registry, this, null)); } return prototype; } /** * Sets the prototype, creating the prototype object from the given * base type. * @param baseType The base type. */ public void setPrototypeBasedOn(ObjectType baseType) { if (prototype == null) { setPrototype( new FunctionPrototypeType( registry, this, baseType, isNativeObjectType())); } else { prototype.setImplicitPrototype(baseType); } } /** * Sets the prototype. * @param prototype the prototype. If this value is {@code null} it will * silently be discarded. */ public boolean setPrototype(FunctionPrototypeType prototype) { if (prototype == null) { return false; } // getInstanceType fails if the function is not a constructor if (isConstructor() && prototype == getInstanceType()) { return false; } boolean replacedPrototype = prototype != null; this.prototype = prototype; if (isConstructor() || isInterface()) { FunctionType superClass = getSuperClassConstructor(); if (superClass != null) { superClass.addSubType(this); } } if (replacedPrototype) { clearCachedValues(); } return true; } /** * Returns all interfaces implemented by a class or its superclass and any * superclasses for any of those interfaces. If this is called before all * types are resolved, it may return an incomplete set. */ public Iterable<ObjectType> getAllImplementedInterfaces() { // Store them in a linked hash set, so that the compile job is // deterministic. Set<ObjectType> interfaces = Sets.newLinkedHashSet(); for (ObjectType type : getImplementedInterfaces()) { addRelatedInterfaces(type, interfaces); } return interfaces; } private void addRelatedInterfaces(ObjectType instance, Set<ObjectType> set) { FunctionType constructor = instance.getConstructor(); if (constructor != null) { if (!constructor.isInterface()) { return; } set.add(instance); if (constructor.getSuperClassConstructor() != null) {

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> addRelatedInterfaces( constructor.getSuperClassConstructor().getInstanceType(), set); } } } /** Returns interfaces implemented directly by a class or its superclass. */ public Iterable<ObjectType> getImplementedInterfaces() { FunctionType superCtor = isConstructor() ? getSuperClassConstructor() : null; if (superCtor == null) { return implementedInterfaces; } else { return Iterables.concat( implementedInterfaces, superCtor.getImplementedInterfaces()); } } public void setImplementedInterfaces(List<ObjectType> implementedInterfaces) { // Records this type for each implemented interface. for (ObjectType type : implementedInterfaces) { registry.registerTypeImplementingInterface(this, type); } this.implementedInterfaces = ImmutableList.copyOf(implementedInterfaces); } @Override public boolean hasProperty(String name) { return super.hasProperty(name) || "prototype".equals(name); } @Override public boolean hasOwnProperty(String name) { return super.hasOwnProperty(name) || "prototype".equals(name); } @Override public JSType getPropertyType(String name) { if ("prototype".equals(name)) { return getPrototype(); } else { if (!hasOwnProperty(name)) { if ("call".equals(name)) { // Define the "call" function lazily. Node params = getParametersNode(); if (params == null) { // If there's no params array, don't do any type-checking // in this CALL function. defineDeclaredProperty(name, new FunctionBuilder(registry) .withReturnType(getReturnType()) .build(), false, source); } else { params = params.cloneTree(); Node thisTypeNode = Node.newString(Token.NAME, "thisType"); thisTypeNode.setJSType( registry.createOptionalNullableType(getTypeOfThis())); params.addChildToFront(thisTypeNode); thisTypeNode.setOptionalArg(true); defineDeclaredProperty(name, new FunctionBuilder(registry) .withParamsNode(params) .withReturnType(getReturnType()) .build(), false, source); } } else if ("apply".equals(name)) { // Define the "apply" function lazily. FunctionParamBuilder builder = new FunctionParamBuilder(registry); // Ecma-262 says that apply's second argument must be an Array // or an arguments object. We don't model the arguments object, // so let's just be forgiving for now. // TODO(nicksantos): Model the Arguments object. builder.addOptionalParams( registry.createNullableType(getTypeOfThis()), registry.createNullableType( registry.getNativeType(JSTypeNative.OBJECT_TYPE))); defineDeclaredProperty(name, new FunctionBuilder(registry) .withParams(builder) .withReturnType(getReturnType()) .build(), false, source); } } return super.getPropertyType(name); } } @Override boolean defineProperty(String name, JSType type, boolean inferred, boolean inExterns, Node propertyNode) { if ("prototype".equals(name)) { ObjectType objType = type.toObjectType(); if (objType != null) { if (objType.isEquivalentTo(prototype)) { return true; } return setPrototype( new FunctionPrototypeType( registry, this, objType, isNativeObjectType())); } else { return false; } } return super.defineProperty(name, type, inferred, inExterns, propertyNode); } @Override

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> public boolean isPropertyTypeInferred(String property) { return "prototype".equals(property) || super.isPropertyTypeInferred(property); } @Override public JSType getLeastSupertype(JSType that) { return supAndInfHelper(that, true); } @Override public JSType getGreatestSubtype(JSType that) { return supAndInfHelper(that, false); } /** * Computes the supremum or infimum of functions with other types. * Because sup() and inf() share a lot of logic for functions, we use * a single helper. * @param leastSuper If true, compute the supremum of {@code this} with * {@code that}. Otherwise compute the infimum. * @return The least supertype or greatest subtype. */ private JSType supAndInfHelper(JSType that, boolean leastSuper) { // NOTE(nicksantos): When we remove the unknown type, the function types // form a lattice with the universal constructor at the top of the lattice, // and the LEAST_FUNCTION_TYPE type at the bottom of the lattice. // // When we introduce the unknown type, it's much more difficult to make // heads or tails of the partial ordering of types, because there's no // clear hierarchy between the different components (parameter types and // return types) in the ArrowType. // // Rather than make the situation more complicated by introducing new // types (like unions of functions), we just fallback on the simpler // approach of getting things right at the top and the bottom of the // lattice. if (isFunctionType() && that.isFunctionType()) { if (isEquivalentTo(that)) { return this; } FunctionType other = null; if (that instanceof FunctionType) { other = (FunctionType) that; } // If these are ordinary functions, then merge them. // Don't do this if any of the params/return // values are unknown, because then there will be cycles in // their local lattice and they will merge in weird ways. if (other != null && isOrdinaryFunction() && that.isOrdinaryFunction() && !this.call.hasUnknownParamsOrReturn() && !other.call.hasUnknownParamsOrReturn()) { // Check for the degenerate case, but double check // that there's not a cycle. boolean isSubtypeOfThat = this.isSubtype(that); boolean isSubtypeOfThis = that.isSubtype(this); if (isSubtypeOfThat && !isSubtypeOfThis) { return leastSuper ? that : this; } else if (isSubtypeOfThis && !isSubtypeOfThat) { return leastSuper ? this : that; } // Merge the two functions component-wise. FunctionType merged = tryMergeFunctionPiecewise(other, leastSuper); if (merged != null) { return merged; } } // The function instance type is a special case // that lives above the rest of the lattice. JSType functionInstance = registry.getNativeType( JSTypeNative.FUNCTION_INSTANCE_TYPE); if (functionInstance.isEquivalentTo(that)) { return leastSuper ? that : this; } else if (functionInstance.isEquivalentTo(this)) { return leastSuper ? this : that; } // In theory, we should be using the GREATEST_FUNCTION_TYPE as the // greatest function. In practice, we don't because it's way too // broad. The greatest function takes var_args None parameters, which // means that all parameters register a type warning.

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> // // Instead, we use the U2U ctor type, which has unknown type args. FunctionType greatestFn = registry.getNativeFunctionType(JSTypeNative.U2U_CONSTRUCTOR_TYPE); FunctionType leastFn = registry.getNativeFunctionType(JSTypeNative.LEAST_FUNCTION_TYPE); return leastSuper ? greatestFn : leastFn; } return leastSuper ? super.getLeastSupertype(that) : super.getGreatestSubtype(that); } /** * Try to get the sup/inf of two functions by looking at the * piecewise components. */ private FunctionType tryMergeFunctionPiecewise( FunctionType other, boolean leastSuper) { Node newParamsNode = null; if (call.hasEqualParameters(other.call)) { newParamsNode = call.parameters; } else { // If the parameters are not equal, don't try to merge them. // Someday, we should try to merge the individual params. return null; } JSType newReturnType = leastSuper ? call.returnType.getLeastSupertype(other.call.returnType) : call.returnType.getGreatestSubtype(other.call.returnType); ObjectType newTypeOfThis = null; if (isEquivalent(typeOfThis, other.typeOfThis)) { newTypeOfThis = typeOfThis; } else { JSType maybeNewTypeOfThis = leastSuper ? typeOfThis.getLeastSupertype(other.typeOfThis) : typeOfThis.getGreatestSubtype(other.typeOfThis); if (maybeNewTypeOfThis instanceof ObjectType) { newTypeOfThis = (ObjectType) maybeNewTypeOfThis; } else { newTypeOfThis = leastSuper ? registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE) : registry.getNativeObjectType(JSTypeNative.NO_OBJECT_TYPE); } } boolean newReturnTypeInferred = call.returnTypeInferred || other.call.returnTypeInferred; return new FunctionType( registry, null, null, new ArrowType( registry, newParamsNode, newReturnType, newReturnTypeInferred), newTypeOfThis, null, false, false); } /** * Given a constructor or an interface type, get its superclass constructor * or {@code null} if none exists. */ public FunctionType getSuperClassConstructor() { Preconditions.checkArgument(isConstructor() || isInterface()); ObjectType maybeSuperInstanceType = getPrototype().getImplicitPrototype(); if (maybeSuperInstanceType == null) { return null; } return maybeSuperInstanceType.getConstructor(); } /** * Given a constructor or an interface type and a property, finds the * top-most superclass that has the property defined (including this * constructor). */ public JSType getTopMostDefiningType(String propertyName) { Preconditions.checkState(isConstructor() || isInterface()); Preconditions.checkArgument(getPrototype().hasProperty(propertyName)); FunctionType ctor = this; JSType topInstanceType; do { topInstanceType = ctor.getInstanceType(); ctor = ctor.getSuperClassConstructor(); } while (ctor != null && ctor.getPrototype().hasProperty(propertyName)); return topInstanceType; } /** * Two function types are equal if their signatures match. Since they don't * have signatures, two interfaces are equal if their names match. */ @Override public boolean isEquivalentTo(JSType otherType) { if (!(otherType instanceof FunctionType)) { return false; } FunctionType that = (FunctionType) otherType; if (!that.isFunctionType()) {

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> return false; } if (this.isConstructor()) { if (that.isConstructor()) { return this == that; } return false; } if (this.isInterface()) { if (that.isInterface()) { return this.getReferenceName().equals(that.getReferenceName()); } return false; } if (that.isInterface()) { return false; } return this.typeOfThis.isEquivalentTo(that.typeOfThis) && this.call.isEquivalentTo(that.call); } @Override public int hashCode() { return isInterface() ? getReferenceName().hashCode() : call.hashCode(); } public boolean hasEqualCallType(FunctionType otherType) { return this.call.isEquivalentTo(otherType.call); } /** * Informally, a function is represented by * {@code function (params): returnType} where the {@code params} is a comma * separated list of types, the first one being a special * {@code this:T} if the function expects a known type for {@code this}. */ @Override public String toString() { if (this == registry.getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE)) { return "Function"; } StringBuilder b = new StringBuilder(32); b.append("function ("); int paramNum = call.parameters.getChildCount(); boolean hasKnownTypeOfThis = !typeOfThis.isUnknownType(); if (hasKnownTypeOfThis) { if (isConstructor()) { b.append("new:"); } else { b.append("this:"); } b.append(typeOfThis.toString()); } if (paramNum > 0) { if (hasKnownTypeOfThis) { b.append(", "); } Node p = call.parameters.getFirstChild(); if (p.isVarArgs()) { appendVarArgsString(b, p.getJSType()); } else { b.append(p.getJSType().toString()); } p = p.getNext(); while (p != null) { b.append(", "); if (p.isVarArgs()) { appendVarArgsString(b, p.getJSType()); } else { b.append(p.getJSType().toString()); } p = p.getNext(); } } b.append("): "); b.append(call.returnType); return b.toString(); } /** Gets the string representation of a var args param. */ private void appendVarArgsString(StringBuilder builder, JSType paramType) { if (paramType.isUnionType()) { // Remove the optionalness from the var arg. paramType = ((UnionType) paramType).getRestrictedUnion( registry.getNativeType(JSTypeNative.VOID_TYPE)); } builder.append("...[").append(paramType.toString()).append("]"); } /** * A function is a subtype of another if their call methods are related via * subtyping and {@code this} is a subtype of {@code that} with regard to * the prototype chain. */ @Override public boolean isSubtype(JSType that) { if (JSType.isSubtype(this, that)) { return true; } if (that.isFunctionType()) { if (((FunctionType) that).isInterface()) { // Any function can be assigned to an interface function. return true; } if (this.isInterface()) { // An interface function cannot be assigned to anything. return false; } // If

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> functionA is a subtype of functionB, then their "this" types // should be contravariant. However, this causes problems because // of the way we enforce overrides. Because function(this:SubFoo) // is not a subtype of function(this:Foo), our override check treats // this as an error. It also screws up out standard method // for aliasing constructors. Let's punt on all this for now. // TODO(nicksantos): fix this. FunctionType other = (FunctionType) that; boolean treatThisTypesAsCovariant = // If either one of these is a ctor, skip 'this' checking. this.isConstructor() || other.isConstructor() || // An interface 'this'-type is non-restrictive. // In practical terms, if C implements I, and I has a method m, // then any m doesn't necessarily have to C#m's 'this' // type doesn't need to match I. (other.typeOfThis.getConstructor() != null && other.typeOfThis.getConstructor().isInterface()) || // If one of the 'this' types is covariant of the other, // then we'll treat them as covariant (see comment above). other.typeOfThis.isSubtype(this.typeOfThis) || this.typeOfThis.isSubtype(other.typeOfThis); return treatThisTypesAsCovariant && this.call.isSubtype(other.call); } return getNativeType(JSTypeNative.FUNCTION_PROTOTYPE).isSubtype(that); } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseFunctionType(this); } /** * Gets the type of instance of this function. * @throws IllegalStateException if this function is not a constructor * (see {@link #isConstructor()}). */ public ObjectType getInstanceType() { Preconditions.checkState(hasInstanceType()); return typeOfThis; } /** Sets the instance type. This should only be used for special native types. */ void setInstanceType(ObjectType instanceType) { typeOfThis = instanceType; } /** * Returns whether this function type has an instance type. */ public boolean hasInstanceType() { return isConstructor() || isInterface(); } /** * Gets the type of {@code this} in this function. */ public ObjectType getTypeOfThis() { return typeOfThis.isNoObjectType() ? registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE) : typeOfThis; } /** * Gets the source node or null if this is an unknown function. */ public Node getSource() { return source; } /** * Sets the source node. */ public void setSource(Node source) { this.source = source; } /** Adds a type to the list of subtypes for this type. */ private void addSubType(FunctionType subType) { if (subTypes == null) { subTypes = Lists.newArrayList(); } subTypes.add(subType); } @Override void clearCachedValues() { super.clearCachedValues(); if (subTypes != null) { for (FunctionType subType : subTypes) { subType.clearCachedValues(); } } if (!isNativeObjectType()) { if (hasInstanceType()) { getInstanceType().clearCachedValues(); } if (prototype != null) { prototype.clearCachedValues(); } } } /** * Returns a list of types that are subtypes of this type. This is only valid

Closure, 82

<FILEB>
<CHANGES>
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
<CHANGEE>
<FILEE>
<FILEB> return displayName != null && !displayName.isEmpty(); } /** * If we see a type name without braces, it might be legacy jsdoc. * So we shouldn't emit warnings about it. This method is how we skip * those warnings. */ void forgiveUnknownNames() {} public boolean isNoType() { return false; } public boolean isNoResolvedType() { return false; } public boolean isNoObjectType() { return false; } public final boolean isEmptyType() { <CHANGES> return isNoType() || isNoObjectType() || isNoResolvedType(); <CHANGEE> } public boolean isNumberObjectType() { return false; } public boolean isNumberValueType() { return false; } /** Whether this is the prototype of a function. */ public boolean isFunctionPrototypeType() { return false; } public boolean isStringObjectType() { <FILEE> <SCANS> * for constructor functions, and may be null. This allows a downward * traversal of the subtype graph. */ public List<FunctionType> getSubTypes() { return subTypes; } @Override public boolean hasCachedValues() { return prototype != null || super.hasCachedValues(); } /** * Gets the template type name. */ public String getTemplateTypeName() { return templateTypeName; } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { setResolvedTypeInternal(this); call = (ArrowType) safeResolve(call, t, scope); prototype = (FunctionPrototypeType) safeResolve(prototype, t, scope); // Warning about typeOfThis if it doesn't resolve to an ObjectType // is handled further upstream. // // TODO(nicksantos): Handle this correctly if we have a UnionType. // // TODO(nicksantos): In ES3, the runtime coerces "null" to the global // activation object. In ES5, it leaves it as null. Just punt on this // issue for now by coercing out null. This is complicated by the // fact that when most people write @this {Foo}, they really don't // mean "nullable Foo". For certain tags (like @extends) we de-nullify // the name for them. JSType maybeTypeOfThis = safeResolve(typeOfThis, t, scope); if (maybeTypeOfThis != null) { maybeTypeOfThis = maybeTypeOfThis.restrictByNotNullOrUndefined(); } if (maybeTypeOfThis instanceof ObjectType) { typeOfThis = (ObjectType) maybeTypeOfThis; } boolean changed = false; ImmutableList.Builder<ObjectType> resolvedInterfaces = ImmutableList.builder(); for (ObjectType iface : implementedInterfaces) { ObjectType resolvedIface = (ObjectType) iface.resolve(t, scope); resolvedInterfaces.add(resolvedIface); changed |= (resolvedIface != iface); } if (changed) { implementedInterfaces = resolvedInterfaces.build(); } if (subTypes != null) { for (int i = 0; i < subTypes.size(); i++) { subTypes.set(i, (FunctionType) subTypes.get(i).resolve(t, scope)); } } return super.resolveInternal(t, scope); } @Override public String toDebugHashCodeString() { if (this == registry.getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE)) { return super.toDebugHashCodeString(); } StringBuilder b = new StringBuilder(32); b.append("function ("); int paramNum = call.parameters.getChildCount(); boolean hasKnownTypeOfThis = !typeOfThis.isUnknownType(); if (hasKnownTypeOfThis) { b.append("this:"); b.append(getDebugHashCodeStringOf(typeOfThis)); } if (paramNum > 0) { if (hasKnownTypeOfThis) { b.append(", "); } Node p = call.parameters.getFirstChild(); b.append(getDebugHashCodeStringOf(p.getJSType())); p = p.getNext(); while (p != null) { b.append(", "); b.append(getDebugHashCodeStringOf(p.getJSType())); p = p.getNext(); } } b.append(")"); b.append(": "); b.append(getDebugHashCodeStringOf(call.returnType)); return b.toString(); } private String getDebugHashCodeStringOf(JSType type) { if (type == this